|
From: Brenda L. <asp...@us...> - 2003-05-13 22:27:19
|
Update of /cvsroot/squeak/squeak/platforms/unix/plugins/SoundPlugin/zzz
In directory sc8-pr-cvs1:/tmp/cvs-serv21322/SoundPlugin/zzz
Added Files:
Buffer.h DoubleBuffer.h Fifo.h ring.h
Log Message:
Ian Piumarta's release 3.5-1devel
--- NEW FILE: Buffer.h ---
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
enum {
Block_Free;
Block_Busy;
Block_Full;
Block_Done;
};
typedef struct
{
int state;
int capacity;
int size;
char *data;
} Block;
Block *Block_new(int size)
{
size &= ~(4 * sizeof(double) - 1);
Block *b= (Block *)calloc(1, sizeof(Block));
if (b)
{
b->state= Block_Free;
b->capacity= size;
if ((b->data= (char *)calloc(1, size)))
return b;
free(b);
}
return 0;
}
void Block_delete(Block *b)
{
free(b->data);
free(b);
}
void Block_reset(Block *b)
{
b->state= Block_Free;
b->size= 0;
}
typedef struct
{
Block *input;
Block *output;
} Buffer;
Buffer *Buffer_new(int size)
{
Buffer *b= (Buffer *)calloc(1, sizeof(Buffer));
if (b)
{
if ((b->input= Block_new(size)))
{
if ((b->output= Block_new(size)))
return b;
Buffer_delete(b->input);
}
free(b);
}
return 0;
}
void Buffer_delete(Buffer *b)
{
Block_delete(b->input);
Block_delete(b->output);
delete(b);
}
int Buffer_swap(Buffer *b)
{
if (input->state == Block_Full)
{
Block *b= input;
Block_reset(b->output);
b->input= b->output;
b->output= b->input;
return 1;
}
output->state= Block_done;
return 0;
}
--- NEW FILE: DoubleBuffer.h ---
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
enum {
Buffer_Free,
Buffer_Busy,
Buffer_Full,
Buffer_Done
};
typedef struct
{
int state;
int size;
int iptr;
int optr; // 0 <= optr <= iptr <= size
char *data;
} Buffer;
Buffer *Buffer_new(int size)
{
Buffer *b= (Buffer *)calloc(1, sizeof(Buffer));
if (b)
{
b->state= Buffer_Free;
b->size= size;
if ((b->data= (char *)calloc(1, size)))
return b;
free(b);
}
return 0;
}
void Buffer_delete(Buffer *b)
{
assert(b && b->data);
free(b->data);
free(b);
}
void Buffer_reset(Buffer *b)
{
b->state= Buffer_Free;
b->iptr= b->optr= 0;
}
int Buffer_avail(Buffer *b)
{
return b->iptr - b->optr;
}
int Buffer_free(Buffer *b)
{
return b->size - b->iptr;
}
typedef struct
{
Buffer *input;
Buffer *output;
} DBuffer;
DBuffer *DBuffer_new(int size)
{
DBuffer *d= (DBuffer *)calloc(1, sizeof(DBuffer));
if (d)
{
if ((d->input= Buffer_new(size)))
{
if ((d->output= Buffer_new(size)))
return d;
Buffer_delete(d->input);
}
free(d);
}
return 0;
}
void DBuffer_delete(DBuffer *d)
{
assert(d && d->input && d->output);
Buffer_delete(d->input);
Buffer_delete(d->output);
free(d);
}
int DBuffer_swap(DBuffer *d)
{
if (d->input->state == Buffer_Full)
{
Buffer *i= d->output;
Buffer *o= d->input;
d->input= i;
d->output= o;
Buffer_reset(i);
return 1;
}
d->output->state= Buffer_done;
return 0;
}
--- NEW FILE: Fifo.h ---
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
// NOTE: requires the client to define min and max on ints
typedef struct
{
char *data;
int size;
int avail;
int iptr;
int optr;
} Buffer;
Buffer *Buffer_new(int size)
{
Buffer *b= (Buffer *)malloc(sizeof(Buffer));
if (!b)
return 0;
if (!(b->data= (char *)malloc(size)))
{
free(b);
return 0;
}
b->size= size;
b->avail= 0;
b->iptr= 0;
b->optr= 0;
return b;
}
void Buffer_delete(Buffer *b)
{
assert(b && b->data);
free(b->data);
free(b);
}
inline int Buffer_avail(Buffer *b)
{
assert(!(b->avail & 3));
return b->avail;
}
inline int Buffer_free(Buffer *b)
{
return b->size - Buffer_avail(b);
}
inline void Buffer_getOutputPointers(Buffer *b, char **p1, int *n1, char **p2, int *n2)
{
int optr= b->optr;
int avail= Buffer_avail(b);
int headroom= b->size - optr;
if (avail == 0)
{
*p1= *p2= 0;
*n1= *n2= 0;
}
else if (avail <= headroom)
{
*p1= b->data + optr; *p2= 0;
*n1= avail; *n2= 0;
}
else
{
*p1= b->data + optr; *p2= b->data;
*n1= headroom; *n2= avail - headroom;
}
assert(!(*n1 & 3));
assert(!(*n2 & 3));
}
inline int Buffer_getOutputPointer(Buffer *b, char **ptr)
{
int optr= b->optr;
int avail= Buffer_avail(b);
int headroom= b->size - optr;
if (headroom < avail) avail= headroom;
assert((optr + avail) <= b->size);
*ptr= b->data + optr;
return avail;
}
inline int Buffer_getInputPointer(Buffer *b, char **ptr)
{
int iptr= b->iptr;
int free= Buffer_free(b);
int headroom= b->size - iptr;
if (headroom < free) free= headroom;
assert((iptr + free) <= b->size);
*ptr= b->data + iptr;
return free;
}
inline void Buffer_advanceOutputPointer(Buffer *b, int size)
{
int optr= b->optr;
int avail= b->avail;
assert(!(size & 3));
optr+= size;
avail-= size;
assert(optr <= b->size);
assert(avail >= 0);
if (optr == b->size) optr= 0;
b->optr= optr;
b->avail= avail;
}
inline void Buffer_advanceInputPointer(Buffer *b, int size)
{
int iptr= b->iptr;
assert(!(size & 3));
{
int free= Buffer_free(b);
free-= size;
assert(free >= 0);
}
iptr += size;
assert(iptr <= b->size);
if (iptr == b->size) iptr= 0;
b->iptr= iptr;
b->avail += size;
}
inline void Buffer_prefill(Buffer *b, int bytes)
{
char *ptr;
int size= Buffer_getInputPointer(b, &ptr);
assert(!(bytes & 3));
assert(bytes <= size);
memset(ptr, 0, size);
Buffer_advanceInputPointer(b, bytes);
}
inline int Buffer_write(Buffer *b, char *buf, int nbytes)
{
int iptr= b->iptr;
int bytesToCopy= min(nbytes, Buffer_free(b));
int headroom= b->size - iptr;
int bytesCopied= 0;
assert(!(nbytes & 3));
if (bytesToCopy >= headroom)
{
memcpy(b->data + iptr, buf, headroom);
iptr= 0;
bytesToCopy -= headroom;
bytesCopied += headroom;
if (bytesToCopy)
{
memcpy(b->data, buf + bytesCopied, bytesToCopy);
iptr= bytesToCopy;
bytesCopied += bytesToCopy;
}
}
else
{
memcpy(b->data + iptr, buf, bytesToCopy);
iptr += bytesToCopy;
bytesCopied= bytesToCopy;
}
b->iptr= iptr;
b->avail += bytesCopied;
return bytesCopied;
}
inline int Buffer_read(Buffer *b, char *buf, int nbytes)
{
int optr= b->optr;
int bytesToCopy= min(nbytes, Buffer_avail(b));
int headroom= b->size - optr;
int bytesCopied= 0;
assert(!(nbytes & 3));
if (bytesToCopy >= headroom)
{
memcpy(buf, b->data + optr, headroom);
optr= 0;
bytesToCopy -= headroom;
bytesCopied += headroom;
if (bytesToCopy)
{
memcpy(buf + bytesCopied, b->data, bytesToCopy);
optr= bytesToCopy;
bytesCopied += bytesToCopy;
}
}
else
{
memcpy(buf, b->data + optr, bytesToCopy);
optr += bytesToCopy;
bytesCopied= bytesToCopy;
}
b->optr= optr;
b->avail -= bytesCopied;
return bytesCopied;
}
--- NEW FILE: ring.h ---
// ring.h -- lightweight ring buffers for sound i/o
//
// Author: Ian...@IN...
//
// Last edited:
//
// Copyright (C) 1996-2002 Ian Piumarta and other authors/contributors
// as listed elsewhere in this file.
// All rights reserved.
//
// You are NOT ALLOWED to distribute modified versions of this file
// under its original name. If you want to modify it and then make
// your modifications available publicly, rename the file first.
//
// This file is part of Unix Squeak.
//
// 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;
}
|