|
|
AL_EXT_PAIR(alCaptureStop_EXT), | AL_EXT_PAIR(alCaptureStop_EXT), |
AL_EXT_PAIR(alCaptureGetData_EXT), | AL_EXT_PAIR(alCaptureGetData_EXT), |
AL_EXT_PAIR(alCaptureDestroy_EXT), | AL_EXT_PAIR(alCaptureDestroy_EXT), |
|
AL_EXT_PAIR(alcCaptureOpenDevice), |
|
AL_EXT_PAIR(alcCaptureCloseDevice), |
|
AL_EXT_PAIR(alcCaptureStart), |
|
AL_EXT_PAIR(alcCaptureStop), |
|
AL_EXT_PAIR(alcCaptureSamples), |
{ NULL, NULL } | { NULL, NULL } |
}; | }; |
| |
|
|
return; | return; |
} | } |
| |
ALboolean alCaptureInit_EXT( UNUSED(ALenum format), |
ALboolean alCaptureInit_EXT( ALenum format, |
UNUSED(ALuint rate), |
ALuint rate, |
UNUSED(ALsizei bufferSize) ) | UNUSED(ALsizei bufferSize) ) |
{ | { |
ALuint cid; | ALuint cid; |
|
|
capture_device = cc->read_device; | capture_device = cc->read_device; |
if ( capture_device == NULL ) { | if ( capture_device == NULL ) { |
char spec[1024]; | char spec[1024]; |
char *fmt="'( (direction \"read\") (sampling-rate %d))"; |
int speakers; |
|
char *fmt="'( (direction \"read\") (sampling-rate %d) (speaker-num %d) )"; |
|
|
|
switch (format) { |
|
case AL_FORMAT_MONO8: |
|
case AL_FORMAT_MONO16: |
|
default: |
|
speakers = 1; |
|
break; |
|
case AL_FORMAT_STEREO8: |
|
case AL_FORMAT_STEREO16: |
|
speakers = 2; |
|
break; |
|
case AL_FORMAT_QUAD8_LOKI: |
|
case AL_FORMAT_QUAD16_LOKI: |
|
speakers = 4; |
|
break; |
|
} |
|
|
|
sprintf(spec, fmt, rate, speakers); |
| |
sprintf(spec, fmt, rate); |
|
capture_device = alcOpenDevice((ALubyte *)spec); | capture_device = alcOpenDevice((ALubyte *)spec); |
if ( capture_device ) { | if ( capture_device ) { |
_alcSetContext(NULL, cid, capture_device); | _alcSetContext(NULL, cid, capture_device); |
|
|
AL_TRUE); | AL_TRUE); |
} else { | } else { |
/* Hmm, zero size in record.. */ | /* Hmm, zero size in record.. */ |
memset(temp, 0, n); |
/*memset(temp, 0, n); */ |
size = n; |
size = 0; |
} | } |
if(temp == NULL) { | if(temp == NULL) { |
fprintf(stderr, "could not canonize data\n"); | fprintf(stderr, "could not canonize data\n"); |
|
|
} | } |
return size; | return size; |
} | } |
|
|
|
|
|
/* Hacked in ALC_EXT_capture support. --ryan. */ |
|
/* This doesn't support multiple devices, device enumeration, or capture */ |
|
/* devices seperate from an existing context. How painful. */ |
|
|
|
/* ring buffer functionality... */ |
|
|
|
typedef struct |
|
{ |
|
ALubyte *buffer; |
|
ALsizei size; |
|
ALsizei write; |
|
ALsizei read; |
|
ALsizei used; |
|
} __ALRingBuffer; |
|
|
|
static ALboolean __alRingBufferInit(__ALRingBuffer *ring, ALsizei size); |
|
static ALvoid __alRingBufferShutdown(__ALRingBuffer *ring); |
|
static ALsizei __alRingBufferSize(__ALRingBuffer *ring); |
|
static ALvoid __alRingBufferPut(__ALRingBuffer *ring, ALubyte *data, ALsizei size); |
|
static ALsizei __alRingBufferGet(__ALRingBuffer *ring, ALubyte *data, ALsizei size); |
|
|
|
static __ALRingBuffer captureRing; |
|
|
|
static ALboolean __alRingBufferInit(__ALRingBuffer *ring, ALsizei size) |
|
{ |
|
ALubyte *ptr = (ALubyte *) realloc(ring->buffer, size); |
|
if (ptr == NULL) |
|
return(AL_FALSE); |
|
|
|
ring->buffer = ptr; |
|
ring->size = size; |
|
ring->write = 0; |
|
ring->read = 0; |
|
ring->used = 0; |
|
return(AL_TRUE); |
|
} /* __alRingBufferInit */ |
|
|
|
static ALvoid __alRingBufferShutdown(__ALRingBuffer *ring) |
|
{ |
|
free(ring->buffer); |
|
ring->buffer = NULL; |
|
} /* __alRingBufferShutdown */ |
|
|
|
static ALsizei __alRingBufferSize(__ALRingBuffer *ring) |
|
{ |
|
return(ring->used); |
|
} /* __alRingBufferSize */ |
|
|
|
static ALvoid __alRingBufferPut(__ALRingBuffer *ring, ALubyte *data, ALsizei _size) |
|
{ |
|
register ALsizei size = _size; |
|
register ALsizei cpy; |
|
register ALsizei avail; |
|
|
|
if (!size) /* just in case... */ |
|
return; |
|
|
|
/* Putting more data than ring buffer holds in total? Replace it all. */ |
|
if (size > ring->size) |
|
{ |
|
ring->write = 0; |
|
ring->read = 0; |
|
ring->used = ring->size; |
|
memcpy(ring->buffer, data + (size - ring->size), ring->size); |
|
return; |
|
} /* if */ |
|
|
|
/* Buffer overflow? Push read pointer to oldest sample not overwritten. */ |
|
avail = ring->size - ring->used; |
|
if (size > avail) |
|
{ |
|
ring->read += size - avail; |
|
if (ring->read > ring->size) |
|
ring->read -= ring->size; |
|
} /* if */ |
|
|
|
/* Clip to end of buffer and copy first block... */ |
|
cpy = ring->size - ring->write; |
|
if (size < cpy) |
|
cpy = size; |
|
if (cpy) memcpy(ring->buffer + ring->write, data, cpy); |
|
|
|
/* Wrap around to front of ring buffer and copy remaining data... */ |
|
avail = size - cpy; |
|
if (avail) memcpy(ring->buffer, data + cpy, avail); |
|
|
|
/* Update write pointer... */ |
|
ring->write += size; |
|
if (ring->write > ring->size) |
|
ring->write -= ring->size; |
|
|
|
ring->used += size; |
|
if (ring->used > ring->size) |
|
ring->used = ring->size; |
|
} /* __alRingBufferPut */ |
|
|
|
static ALsizei __alRingBufferGet(__ALRingBuffer *ring, ALubyte *data, ALsizei _size) |
|
{ |
|
register ALsizei cpy; |
|
register ALsizei size = _size; |
|
register ALsizei avail = ring->used; |
|
|
|
/* Clamp amount to read to available data... */ |
|
if (size > avail) |
|
size = avail; |
|
|
|
/* Clip to end of buffer and copy first block... */ |
|
cpy = ring->size - ring->read; |
|
if (cpy > size) cpy = size; |
|
if (cpy) memcpy(data, ring->buffer + ring->read, cpy); |
|
|
|
/* Wrap around to front of ring buffer and copy remaining data... */ |
|
avail = size - cpy; |
|
if (avail) memcpy(data + cpy, ring->buffer, avail); |
|
|
|
/* Update read pointer... */ |
|
ring->read += size; |
|
if (ring->read > ring->size) |
|
ring->read -= ring->size; |
|
|
|
ring->used -= size; |
|
|
|
return(size); /* may have been clamped if there wasn't enough data... */ |
|
} /* __alRingBufferGet */ |
|
|
|
static ALenum captureFmt = AL_NONE; |
|
static ALuint captureFreq = 0; |
|
static ALint captureFmtSize = 0; |
|
|
|
ALCdevice *alcCaptureOpenDevice(const ALubyte *deviceName, |
|
ALuint freq, ALenum fmt, |
|
ALsizei bufsize) |
|
{ |
|
ALCdevice *retval; |
|
AL_context *cc; |
|
ALuint cid; |
|
|
|
if (deviceName != NULL) /* !!! FIXME */ |
|
return NULL; |
|
|
|
switch (fmt) /* try to keep this sane for now... */ |
|
{ |
|
case AL_FORMAT_MONO8: |
|
case AL_FORMAT_MONO16: |
|
case AL_FORMAT_STEREO8: |
|
case AL_FORMAT_STEREO16: |
|
break; /* okay format. */ |
|
|
|
default: |
|
return(NULL); |
|
} |
|
|
|
captureFmt = fmt; |
|
captureFreq = freq; |
|
captureFmtSize = (_al_formatbits(fmt) / 8); |
|
if ((fmt == AL_FORMAT_STEREO8) || (fmt == AL_FORMAT_STEREO16)) |
|
captureFmtSize *= 2; |
|
|
|
bufsize *= captureFmtSize; |
|
|
|
if (!__alRingBufferInit(&captureRing, bufsize)) |
|
return NULL; |
|
|
|
if (!alCaptureInit_EXT(fmt, freq, bufsize)) |
|
return NULL; |
|
|
|
cid = _alcCCId; |
|
_alcLockContext( cid ); |
|
cc = _alcGetContext(cid); |
|
retval = cc->read_device; |
|
retval->cc = cc; |
|
_alcUnlockContext( cid ); |
|
|
|
fprintf(stderr, "WARNING: ALC_EXT_capture is subject to change!\n"); |
|
|
|
return(retval); |
|
} |
|
|
|
ALvoid alcCaptureCloseDevice(ALCdevice *dev) |
|
{ |
|
if (dev == NULL) |
|
return; |
|
|
|
alCaptureDestroy_EXT(); |
|
__alRingBufferShutdown(&captureRing); |
|
} |
|
|
|
ALvoid alcCaptureStart(void) |
|
{ |
|
alCaptureStart_EXT(); |
|
} |
|
|
|
ALvoid alcCaptureStop(void) |
|
{ |
|
alCaptureStop_EXT(); |
|
} |
|
|
|
/* !!! FIXME: Not ideal; reads samples in ALC_CAPTURE_SAMPLES query */ |
|
/* !!! FIXME: should query hardware here and do read in alcCaptureSamples() */ |
|
ALint __alcGetAvailableSamples(ALvoid) |
|
{ |
|
static ALubyte buf[2048]; |
|
ALsizei got; |
|
|
|
while ((got = alCaptureGetData_EXT(buf, sizeof (buf), |
|
captureFmt, captureFreq)) > 0) |
|
__alRingBufferPut(&captureRing, buf, got); |
|
/*printf("got %d have %d\n", (int) got, (int) (__alRingBufferSize(&captureRing) / captureFmtSize));*/ |
|
|
|
return(__alRingBufferSize(&captureRing) / captureFmtSize); |
|
} |
|
|
|
|
|
ALvoid alcCaptureSamples(UNUSED(ALCdevice *device), ALvoid *buf, ALsizei samps) |
|
{ |
|
if ((__alRingBufferSize(&captureRing) / captureFmtSize) < samps) |
|
return; /* !!! FIXME: This is an error condition! */ |
|
|
|
__alRingBufferGet(&captureRing, buf, samps * captureFmtSize); |
|
} |
|
|