dos2unix
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@968 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
0232f398c7
commit
df1f3209d9
|
@ -1,333 +1,333 @@
|
||||||
/*
|
/*
|
||||||
* $Id: pablio.c,v 1.1.1.1.4.4 2003/03/13 17:28:33 philburk Exp $
|
* $Id: pablio.c,v 1.1.1.1.4.4 2003/03/13 17:28:33 philburk Exp $
|
||||||
* pablio.c
|
* pablio.c
|
||||||
* Portable Audio Blocking Input/Output utility.
|
* Portable Audio Blocking Input/Output utility.
|
||||||
*
|
*
|
||||||
* Author: Phil Burk, http://www.softsynth.com
|
* Author: Phil Burk, http://www.softsynth.com
|
||||||
*
|
*
|
||||||
* This program uses the PortAudio Portable Audio Library.
|
* This program uses the PortAudio Portable Audio Library.
|
||||||
* For more information see: http://www.audiomulch.com/portaudio/
|
* For more information see: http://www.audiomulch.com/portaudio/
|
||||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files
|
* a copy of this software and associated documentation files
|
||||||
* (the "Software"), to deal in the Software without restriction,
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
* including without limitation the rights to use, copy, modify, merge,
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
* and to permit persons to whom the Software is furnished to do so,
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
* subject to the following conditions:
|
* subject to the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be
|
* The above copyright notice and this permission notice shall be
|
||||||
* included in all copies or substantial portions of the Software.
|
* included in all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* Any person wishing to distribute modifications to the Software is
|
* Any person wishing to distribute modifications to the Software is
|
||||||
* requested to send the modifications to the original developer so that
|
* requested to send the modifications to the original developer so that
|
||||||
* they can be incorporated into the canonical version.
|
* they can be incorporated into the canonical version.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* History:
|
/* History:
|
||||||
* PLB021214 - check for valid stream in CloseAudioStream() to prevent hang.
|
* PLB021214 - check for valid stream in CloseAudioStream() to prevent hang.
|
||||||
* add timeOutMSec to CloseAudioStream() to prevent hang.
|
* add timeOutMSec to CloseAudioStream() to prevent hang.
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "portaudio.h"
|
#include "portaudio.h"
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include "pablio.h"
|
#include "pablio.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/******** Constants *****************************************************/
|
/******** Constants *****************************************************/
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
#define FRAMES_PER_BUFFER (256)
|
#define FRAMES_PER_BUFFER (256)
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/******** Prototypes ****************************************************/
|
/******** Prototypes ****************************************************/
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
static int blockingIOCallback(void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
|
static int blockingIOCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,
|
||||||
PaTimestamp outTime, void *userData);
|
PaTimestamp outTime, void *userData);
|
||||||
static PaError PABLIO_InitFIFO(RingBuffer * rbuf, long numFrames, long bytesPerFrame);
|
static PaError PABLIO_InitFIFO(RingBuffer * rbuf, long numFrames, long bytesPerFrame);
|
||||||
static PaError PABLIO_TermFIFO(RingBuffer * rbuf);
|
static PaError PABLIO_TermFIFO(RingBuffer * rbuf);
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/******** Functions *****************************************************/
|
/******** Functions *****************************************************/
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
/* Called from PortAudio.
|
/* Called from PortAudio.
|
||||||
* Read and write data only if there is room in FIFOs.
|
* Read and write data only if there is room in FIFOs.
|
||||||
*/
|
*/
|
||||||
static int blockingIOCallback(void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
|
static int blockingIOCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,
|
||||||
PaTimestamp outTime, void *userData)
|
PaTimestamp outTime, void *userData)
|
||||||
{
|
{
|
||||||
PABLIO_Stream * data = (PABLIO_Stream *) userData;
|
PABLIO_Stream * data = (PABLIO_Stream *) userData;
|
||||||
long numBytes = data->bytesPerFrame * framesPerBuffer;
|
long numBytes = data->bytesPerFrame * framesPerBuffer;
|
||||||
(void) outTime;
|
(void) outTime;
|
||||||
|
|
||||||
/* This may get called with NULL inputBuffer during initial setup. */
|
/* This may get called with NULL inputBuffer during initial setup. */
|
||||||
if (inputBuffer != NULL)
|
if (inputBuffer != NULL)
|
||||||
{
|
{
|
||||||
RingBuffer_Write(&data->inFIFO, inputBuffer, numBytes);
|
RingBuffer_Write(&data->inFIFO, inputBuffer, numBytes);
|
||||||
}
|
}
|
||||||
if (outputBuffer != NULL)
|
if (outputBuffer != NULL)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int numRead = RingBuffer_Read(&data->outFIFO, outputBuffer, numBytes);
|
int numRead = RingBuffer_Read(&data->outFIFO, outputBuffer, numBytes);
|
||||||
|
|
||||||
/* Zero out remainder of buffer if we run out of data. */
|
/* Zero out remainder of buffer if we run out of data. */
|
||||||
for (i = numRead; i < numBytes; i++)
|
for (i = numRead; i < numBytes; i++)
|
||||||
{
|
{
|
||||||
((char *) outputBuffer)[i] = 0;
|
((char *) outputBuffer)[i] = 0;
|
||||||
}
}
|
} }
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Allocate buffer. */
|
/* Allocate buffer. */
|
||||||
static PaError PABLIO_InitFIFO(RingBuffer * rbuf, long numFrames, long bytesPerFrame)
|
static PaError PABLIO_InitFIFO(RingBuffer * rbuf, long numFrames, long bytesPerFrame)
|
||||||
{
|
{
|
||||||
long numBytes = numFrames * bytesPerFrame;
|
long numBytes = numFrames * bytesPerFrame;
|
||||||
char *buffer = (char *) malloc(numBytes);
|
char *buffer = (char *) malloc(numBytes);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
return paInsufficientMemory;
|
return paInsufficientMemory;
|
||||||
memset(buffer, 0, numBytes);
|
memset(buffer, 0, numBytes);
|
||||||
return (PaError) RingBuffer_Init(rbuf, numBytes, buffer);
|
return (PaError) RingBuffer_Init(rbuf, numBytes, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Free buffer. */
|
/* Free buffer. */
|
||||||
static PaError PABLIO_TermFIFO(RingBuffer * rbuf)
|
static PaError PABLIO_TermFIFO(RingBuffer * rbuf)
|
||||||
{
|
{
|
||||||
if (rbuf->buffer)
|
if (rbuf->buffer)
|
||||||
free(rbuf->buffer);
|
free(rbuf->buffer);
|
||||||
rbuf->buffer = NULL;
|
rbuf->buffer = NULL;
|
||||||
return paNoError;
|
return paNoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* Write data to ring buffer.
|
* Write data to ring buffer.
|
||||||
* Will not return until all the data has been written.
|
* Will not return until all the data has been written.
|
||||||
*/
|
*/
|
||||||
long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames)
|
long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames)
|
||||||
{
|
{
|
||||||
long bytesWritten;
|
long bytesWritten;
|
||||||
char *p = (char *) data;
|
char *p = (char *) data;
|
||||||
long numBytes = aStream->bytesPerFrame * numFrames;
|
long numBytes = aStream->bytesPerFrame * numFrames;
|
||||||
while (numBytes > 0)
|
while (numBytes > 0)
|
||||||
{
|
{
|
||||||
bytesWritten = RingBuffer_Write(&aStream->outFIFO, p, numBytes);
|
bytesWritten = RingBuffer_Write(&aStream->outFIFO, p, numBytes);
|
||||||
numBytes -= bytesWritten;
|
numBytes -= bytesWritten;
|
||||||
p += bytesWritten;
|
p += bytesWritten;
|
||||||
if (numBytes > 0)
|
if (numBytes > 0)
|
||||||
Pa_Sleep(10);
|
Pa_Sleep(10);
|
||||||
}
|
}
|
||||||
return numFrames;
|
return numFrames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* Read data from ring buffer.
|
* Read data from ring buffer.
|
||||||
* Will not return until all the data has been read.
|
* Will not return until all the data has been read.
|
||||||
*/
|
*/
|
||||||
long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames)
|
long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames)
|
||||||
{
|
{
|
||||||
long bytesRead;
|
long bytesRead;
|
||||||
char *p = (char *) data;
|
char *p = (char *) data;
|
||||||
long numBytes = aStream->bytesPerFrame * numFrames;
|
long numBytes = aStream->bytesPerFrame * numFrames;
|
||||||
while (numBytes > 0)
|
while (numBytes > 0)
|
||||||
{
|
{
|
||||||
bytesRead = RingBuffer_Read(&aStream->inFIFO, p, numBytes);
|
bytesRead = RingBuffer_Read(&aStream->inFIFO, p, numBytes);
|
||||||
numBytes -= bytesRead;
|
numBytes -= bytesRead;
|
||||||
p += bytesRead;
|
p += bytesRead;
|
||||||
if (numBytes > 0)
|
if (numBytes > 0)
|
||||||
Pa_Sleep(10);
|
Pa_Sleep(10);
|
||||||
}
|
}
|
||||||
return numFrames;
|
return numFrames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************************************************
|
|
||||||
* Return the number of frames that could be written to the stream without
|
|
||||||
* having to wait.
|
|
||||||
*/
|
|
||||||
long GetAudioStreamWriteable(PABLIO_Stream * aStream)
|
|
||||||
{
|
|
||||||
int bytesEmpty = RingBuffer_GetWriteAvailable(&aStream->outFIFO);
|
|
||||||
return bytesEmpty / aStream->bytesPerFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
/************************************************************
|
* Return the number of frames that could be written to the stream without
|
||||||
* Return the number of frames that are available to be read from the
|
* having to wait.
|
||||||
* stream without having to wait.
|
*/
|
||||||
*/
|
long GetAudioStreamWriteable(PABLIO_Stream * aStream)
|
||||||
long GetAudioStreamReadable(PABLIO_Stream * aStream)
|
|
||||||
{
|
{
|
||||||
int bytesFull = RingBuffer_GetReadAvailable(&aStream->inFIFO);
|
int bytesEmpty = RingBuffer_GetWriteAvailable(&aStream->outFIFO);
|
||||||
return bytesFull / aStream->bytesPerFrame;
|
return bytesEmpty / aStream->bytesPerFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************************************************/
|
/************************************************************
|
||||||
static unsigned long RoundUpToNextPowerOf2(unsigned long n)
|
* Return the number of frames that are available to be read from the
|
||||||
|
* stream without having to wait.
|
||||||
|
*/
|
||||||
|
long GetAudioStreamReadable(PABLIO_Stream * aStream)
|
||||||
{
|
{
|
||||||
long numBits = 0;
|
int bytesFull = RingBuffer_GetReadAvailable(&aStream->inFIFO);
|
||||||
if (((n - 1) & n) == 0)
|
return bytesFull / aStream->bytesPerFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************/
|
||||||
|
static unsigned long RoundUpToNextPowerOf2(unsigned long n)
|
||||||
|
{
|
||||||
|
long numBits = 0;
|
||||||
|
if (((n - 1) & n) == 0)
|
||||||
return n; /* Already Power of two. */
|
return n; /* Already Power of two. */
|
||||||
while (n > 0)
|
while (n > 0)
|
||||||
{
|
{
|
||||||
n = n >> 1;
|
n = n >> 1;
|
||||||
numBits++;
|
numBits++;
|
||||||
}
|
}
|
||||||
return (1 << numBits);
|
return (1 << numBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* Opens a PortAudio stream with default characteristics.
|
* Opens a PortAudio stream with default characteristics.
|
||||||
* Allocates PABLIO_Stream structure.
|
* Allocates PABLIO_Stream structure.
|
||||||
*
|
*
|
||||||
* flags parameter can be an ORed combination of:
|
* flags parameter can be an ORed combination of:
|
||||||
* PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
|
* PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
|
||||||
* and either PABLIO_MONO or PABLIO_STEREO
|
* and either PABLIO_MONO or PABLIO_STEREO
|
||||||
*/
|
*/
|
||||||
PaError OpenAudioStream(PABLIO_Stream ** rwblPtr, double sampleRate,
PaSampleFormat format, long flags, int indev,
|
PaError OpenAudioStream(PABLIO_Stream ** rwblPtr, double sampleRate, PaSampleFormat format, long flags, int indev,
|
||||||
int outdev)
|
int outdev)
|
||||||
{
|
{
|
||||||
long bytesPerSample;
|
long bytesPerSample;
|
||||||
long doRead = 0;
|
long doRead = 0;
|
||||||
long doWrite = 0;
|
long doWrite = 0;
|
||||||
PaError err;
|
PaError err;
|
||||||
PABLIO_Stream * aStream;
|
PABLIO_Stream * aStream;
|
||||||
long minNumBuffers;
|
long minNumBuffers;
|
||||||
long numFrames;
|
long numFrames;
|
||||||
|
|
||||||
/* Allocate PABLIO_Stream structure for caller. */
|
/* Allocate PABLIO_Stream structure for caller. */
|
||||||
aStream = (PABLIO_Stream *) malloc(sizeof(PABLIO_Stream));
|
aStream = (PABLIO_Stream *) malloc(sizeof(PABLIO_Stream));
|
||||||
if (aStream == NULL)
|
if (aStream == NULL)
|
||||||
return paInsufficientMemory;
|
return paInsufficientMemory;
|
||||||
memset(aStream, 0, sizeof(PABLIO_Stream));
|
memset(aStream, 0, sizeof(PABLIO_Stream));
|
||||||
|
|
||||||
/* Determine size of a sample. */
|
/* Determine size of a sample. */
|
||||||
bytesPerSample = Pa_GetSampleSize(format);
|
bytesPerSample = Pa_GetSampleSize(format);
|
||||||
if (bytesPerSample < 0)
|
if (bytesPerSample < 0)
|
||||||
{
|
{
|
||||||
err = (PaError) bytesPerSample;
|
err = (PaError) bytesPerSample;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
aStream->samplesPerFrame = ((flags & PABLIO_MONO) != 0) ? 1 : 2;
|
aStream->samplesPerFrame = ((flags & PABLIO_MONO) != 0) ? 1 : 2;
|
||||||
aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame;
|
aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame;
|
||||||
|
|
||||||
/* Initialize PortAudio */
|
/* Initialize PortAudio */
|
||||||
err = Pa_Initialize();
|
err = Pa_Initialize();
|
||||||
if (err != paNoError)
|
if (err != paNoError)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* Warning: numFrames must be larger than amount of data processed per interrupt
|
/* Warning: numFrames must be larger than amount of data processed per interrupt
|
||||||
* inside PA to prevent glitches. Just to be safe, adjust size upwards.
|
* inside PA to prevent glitches. Just to be safe, adjust size upwards.
|
||||||
*/
|
*/
|
||||||
minNumBuffers = 2 * Pa_GetMinNumBuffers(FRAMES_PER_BUFFER, sampleRate);
|
minNumBuffers = 2 * Pa_GetMinNumBuffers(FRAMES_PER_BUFFER, sampleRate);
|
||||||
numFrames = minNumBuffers * FRAMES_PER_BUFFER;
|
numFrames = minNumBuffers * FRAMES_PER_BUFFER;
|
||||||
|
|
||||||
/* The PortAudio callback runs in a high priority thread. But PABLIO
|
/* The PortAudio callback runs in a high priority thread. But PABLIO
|
||||||
* runs in a normal foreground thread. So we may have much worse
|
* runs in a normal foreground thread. So we may have much worse
|
||||||
* latency in PABLIO. So adjust latency to a safe level.
|
* latency in PABLIO. So adjust latency to a safe level.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
const int safeLatencyMSec = 200;
|
const int safeLatencyMSec = 200;
|
||||||
int minLatencyMSec = (int) ((1000 * numFrames) / sampleRate);
|
int minLatencyMSec = (int) ((1000 * numFrames) / sampleRate);
|
||||||
if (minLatencyMSec < safeLatencyMSec)
|
if (minLatencyMSec < safeLatencyMSec)
|
||||||
{
|
{
|
||||||
numFrames = (int) ((safeLatencyMSec * sampleRate) / 1000);
|
numFrames = (int) ((safeLatencyMSec * sampleRate) / 1000);
|
||||||
}
|
}
|
||||||
}
numFrames = RoundUpToNextPowerOf2(numFrames);
|
} numFrames = RoundUpToNextPowerOf2(numFrames);
|
||||||
|
|
||||||
/* Initialize Ring Buffers */
|
/* Initialize Ring Buffers */
|
||||||
doRead = ((flags & PABLIO_READ) != 0);
|
doRead = ((flags & PABLIO_READ) != 0);
|
||||||
doWrite = ((flags & PABLIO_WRITE) != 0);
|
doWrite = ((flags & PABLIO_WRITE) != 0);
|
||||||
if (doRead)
|
if (doRead)
|
||||||
{
|
{
|
||||||
err = PABLIO_InitFIFO(&aStream->inFIFO, numFrames, aStream->bytesPerFrame);
|
err = PABLIO_InitFIFO(&aStream->inFIFO, numFrames, aStream->bytesPerFrame);
|
||||||
if (err != paNoError)
|
if (err != paNoError)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (doWrite)
|
if (doWrite)
|
||||||
{
|
{
|
||||||
long numBytes;
|
long numBytes;
|
||||||
err = PABLIO_InitFIFO(&aStream->outFIFO, numFrames, aStream->bytesPerFrame);
|
err = PABLIO_InitFIFO(&aStream->outFIFO, numFrames, aStream->bytesPerFrame);
|
||||||
if (err != paNoError)
|
if (err != paNoError)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* Make Write FIFO appear full initially. */
|
/* Make Write FIFO appear full initially. */
|
||||||
numBytes = RingBuffer_GetWriteAvailable(&aStream->outFIFO);
|
numBytes = RingBuffer_GetWriteAvailable(&aStream->outFIFO);
|
||||||
RingBuffer_AdvanceWriteIndex(&aStream->outFIFO, numBytes);
|
RingBuffer_AdvanceWriteIndex(&aStream->outFIFO, numBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open a PortAudio stream that we will use to communicate with the underlying
|
/* Open a PortAudio stream that we will use to communicate with the underlying
|
||||||
* audio drivers. */
|
* audio drivers. */
|
||||||
err = Pa_OpenStream(
&aStream->stream,
|
err = Pa_OpenStream(&aStream->stream,
|
||||||
(doRead ? (indev > -1) ? indev : Pa_GetDefaultInputDeviceID() : paNoDevice),
|
(doRead ? (indev > -1) ? indev : Pa_GetDefaultInputDeviceID() : paNoDevice),
|
||||||
(doRead ? aStream->samplesPerFrame : 0),
format,
NULL,
|
(doRead ? aStream->samplesPerFrame : 0), format, NULL,
|
||||||
(doWrite ? (outdev > -1) ? outdev : Pa_GetDefaultOutputDeviceID() : paNoDevice),
|
(doWrite ? (outdev > -1) ? outdev : Pa_GetDefaultOutputDeviceID() : paNoDevice),
|
||||||
(doWrite ? aStream->samplesPerFrame : 0),
format,
NULL,
sampleRate,
FRAMES_PER_BUFFER,
|
(doWrite ? aStream->samplesPerFrame : 0), format, NULL, sampleRate, FRAMES_PER_BUFFER,
|
||||||
minNumBuffers,
paClipOff,
|
minNumBuffers, paClipOff,
|
||||||
/* we won't output out of range samples so don't bother clipping them */
|
/* we won't output out of range samples so don't bother clipping them */
|
||||||
blockingIOCallback,
aStream);
|
blockingIOCallback, aStream);
|
||||||
if (err != paNoError)
|
if (err != paNoError)
|
||||||
goto error;
|
goto error;
|
||||||
err = Pa_StartStream(aStream->stream);
|
err = Pa_StartStream(aStream->stream);
|
||||||
if (err != paNoError)
|
if (err != paNoError)
|
||||||
goto error;
|
goto error;
|
||||||
*rwblPtr = aStream;
|
*rwblPtr = aStream;
|
||||||
return paNoError;
|
return paNoError;
|
||||||
error:
CloseAudioStream(aStream);
|
error:CloseAudioStream(aStream);
|
||||||
*rwblPtr = NULL;
|
*rwblPtr = NULL;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************************************************/
|
/************************************************************/
|
||||||
PaError CloseAudioStream(PABLIO_Stream * aStream)
|
PaError CloseAudioStream(PABLIO_Stream * aStream)
|
||||||
{
|
{
|
||||||
PaError err = paNoError;
|
PaError err = paNoError;
|
||||||
int bytesEmpty;
|
int bytesEmpty;
|
||||||
int byteSize = aStream->outFIFO.bufferSize;
|
int byteSize = aStream->outFIFO.bufferSize;
|
||||||
if (aStream->stream != NULL) /* Make sure stream was opened. PLB021214 */
|
if (aStream->stream != NULL) /* Make sure stream was opened. PLB021214 */
|
||||||
{
|
{
|
||||||
|
|
||||||
/* If we are writing data, make sure we play everything written. */
|
/* If we are writing data, make sure we play everything written. */
|
||||||
if (byteSize > 0)
|
if (byteSize > 0)
|
||||||
{
|
{
|
||||||
int timeOutMSec = 2000;
|
int timeOutMSec = 2000;
|
||||||
bytesEmpty = RingBuffer_GetWriteAvailable(&aStream->outFIFO);
|
bytesEmpty = RingBuffer_GetWriteAvailable(&aStream->outFIFO);
|
||||||
while ((bytesEmpty < byteSize) && (timeOutMSec > 0))
|
while ((bytesEmpty < byteSize) && (timeOutMSec > 0))
|
||||||
{
|
{
|
||||||
Pa_Sleep(20);
|
Pa_Sleep(20);
|
||||||
timeOutMSec -= 20;
|
timeOutMSec -= 20;
|
||||||
bytesEmpty = RingBuffer_GetWriteAvailable(&aStream->outFIFO);
|
bytesEmpty = RingBuffer_GetWriteAvailable(&aStream->outFIFO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = Pa_StopStream(aStream->stream);
|
err = Pa_StopStream(aStream->stream);
|
||||||
if (err != paNoError)
|
if (err != paNoError)
|
||||||
goto error;
|
goto error;
|
||||||
err = Pa_CloseStream(aStream->stream);
|
err = Pa_CloseStream(aStream->stream);
|
||||||
}
|
}
|
||||||
error:
Pa_Terminate();
|
error:Pa_Terminate();
|
||||||
PABLIO_TermFIFO(&aStream->inFIFO);
|
PABLIO_TermFIFO(&aStream->inFIFO);
|
||||||
PABLIO_TermFIFO(&aStream->outFIFO);
|
PABLIO_TermFIFO(&aStream->outFIFO);
|
||||||
free(aStream);
|
free(aStream);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,109 +1,109 @@
|
||||||
#ifndef _PABLIO_H
|
#ifndef _PABLIO_H
|
||||||
#define _PABLIO_H
|
#define _PABLIO_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Id: pablio.h,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $
|
* $Id: pablio.h,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $
|
||||||
* PABLIO.h
|
* PABLIO.h
|
||||||
* Portable Audio Blocking read/write utility.
|
* Portable Audio Blocking read/write utility.
|
||||||
*
|
*
|
||||||
* Author: Phil Burk, http://www.softsynth.com/portaudio/
|
* Author: Phil Burk, http://www.softsynth.com/portaudio/
|
||||||
*
|
*
|
||||||
* Include file for PABLIO, the Portable Audio Blocking I/O Library.
|
* Include file for PABLIO, the Portable Audio Blocking I/O Library.
|
||||||
* PABLIO is built on top of PortAudio, the Portable Audio Library.
|
* PABLIO is built on top of PortAudio, the Portable Audio Library.
|
||||||
* For more information see: http://www.audiomulch.com/portaudio/
|
* For more information see: http://www.audiomulch.com/portaudio/
|
||||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files
|
* a copy of this software and associated documentation files
|
||||||
* (the "Software"), to deal in the Software without restriction,
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
* including without limitation the rights to use, copy, modify, merge,
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
* and to permit persons to whom the Software is furnished to do so,
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
* subject to the following conditions:
|
* subject to the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be
|
* The above copyright notice and this permission notice shall be
|
||||||
* included in all copies or substantial portions of the Software.
|
* included in all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* Any person wishing to distribute modifications to the Software is
|
* Any person wishing to distribute modifications to the Software is
|
||||||
* requested to send the modifications to the original developer so that
|
* requested to send the modifications to the original developer so that
|
||||||
* they can be incorporated into the canonical version.
|
* they can be incorporated into the canonical version.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "portaudio.h"
|
#include "portaudio.h"
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
RingBuffer inFIFO;
|
RingBuffer inFIFO;
|
||||||
RingBuffer outFIFO;
|
RingBuffer outFIFO;
|
||||||
PortAudioStream *stream;
|
PortAudioStream *stream;
|
||||||
int bytesPerFrame;
|
int bytesPerFrame;
|
||||||
int samplesPerFrame;
|
int samplesPerFrame;
|
||||||
}
|
}
|
||||||
PABLIO_Stream;
|
PABLIO_Stream;
|
||||||
|
|
||||||
/* Values for flags for OpenAudioStream(). */
|
/* Values for flags for OpenAudioStream(). */
|
||||||
#define PABLIO_READ (1<<0)
|
#define PABLIO_READ (1<<0)
|
||||||
#define PABLIO_WRITE (1<<1)
|
#define PABLIO_WRITE (1<<1)
|
||||||
#define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE)
|
#define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE)
|
||||||
#define PABLIO_MONO (1<<2)
|
#define PABLIO_MONO (1<<2)
|
||||||
#define PABLIO_STEREO (1<<3)
|
#define PABLIO_STEREO (1<<3)
|
||||||
|
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* Write data to ring buffer.
|
* Write data to ring buffer.
|
||||||
* Will not return until all the data has been written.
|
* Will not return until all the data has been written.
|
||||||
*/
|
*/
|
||||||
long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
|
long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
|
||||||
|
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* Read data from ring buffer.
|
* Read data from ring buffer.
|
||||||
* Will not return until all the data has been read.
|
* Will not return until all the data has been read.
|
||||||
*/
|
*/
|
||||||
long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
|
long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
|
||||||
|
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* Return the number of frames that could be written to the stream without
|
* Return the number of frames that could be written to the stream without
|
||||||
* having to wait.
|
* having to wait.
|
||||||
*/
|
*/
|
||||||
long GetAudioStreamWriteable( PABLIO_Stream *aStream );
|
long GetAudioStreamWriteable( PABLIO_Stream *aStream );
|
||||||
|
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* Return the number of frames that are available to be read from the
|
* Return the number of frames that are available to be read from the
|
||||||
* stream without having to wait.
|
* stream without having to wait.
|
||||||
*/
|
*/
|
||||||
long GetAudioStreamReadable( PABLIO_Stream *aStream );
|
long GetAudioStreamReadable( PABLIO_Stream *aStream );
|
||||||
|
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* Opens a PortAudio stream with default characteristics.
|
* Opens a PortAudio stream with default characteristics.
|
||||||
* Allocates PABLIO_Stream structure.
|
* Allocates PABLIO_Stream structure.
|
||||||
*
|
*
|
||||||
* flags parameter can be an ORed combination of:
|
* flags parameter can be an ORed combination of:
|
||||||
* PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
|
* PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
|
||||||
* and either PABLIO_MONO or PABLIO_STEREO
|
* and either PABLIO_MONO or PABLIO_STEREO
|
||||||
*/
|
*/
|
||||||
PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate,
|
PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate,
|
||||||
PaSampleFormat format, long flags, int indev, int outdev );
|
PaSampleFormat format, long flags, int indev, int outdev );
|
||||||
|
|
||||||
PaError CloseAudioStream( PABLIO_Stream *aStream );
|
PaError CloseAudioStream( PABLIO_Stream *aStream );
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#endif /* _PABLIO_H */
|
#endif /* _PABLIO_H */
|
||||||
|
|
|
@ -1,219 +1,219 @@
|
||||||
/*
|
/*
|
||||||
* $Id: ringbuffer.c,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $
|
* $Id: ringbuffer.c,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $
|
||||||
* ringbuffer.c
|
* ringbuffer.c
|
||||||
* Ring Buffer utility..
|
* Ring Buffer utility..
|
||||||
*
|
*
|
||||||
* Author: Phil Burk, http://www.softsynth.com
|
* Author: Phil Burk, http://www.softsynth.com
|
||||||
*
|
*
|
||||||
* This program uses the PortAudio Portable Audio Library.
|
* This program uses the PortAudio Portable Audio Library.
|
||||||
* For more information see: http://www.audiomulch.com/portaudio/
|
* For more information see: http://www.audiomulch.com/portaudio/
|
||||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files
|
* a copy of this software and associated documentation files
|
||||||
* (the "Software"), to deal in the Software without restriction,
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
* including without limitation the rights to use, copy, modify, merge,
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
* and to permit persons to whom the Software is furnished to do so,
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
* subject to the following conditions:
|
* subject to the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be
|
* The above copyright notice and this permission notice shall be
|
||||||
* included in all copies or substantial portions of the Software.
|
* included in all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* Any person wishing to distribute modifications to the Software is
|
* Any person wishing to distribute modifications to the Software is
|
||||||
* requested to send the modifications to the original developer so that
|
* requested to send the modifications to the original developer so that
|
||||||
* they can be incorporated into the canonical version.
|
* they can be incorporated into the canonical version.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Initialize FIFO.
|
* Initialize FIFO.
|
||||||
* numBytes must be power of 2, returns -1 if not.
|
* numBytes must be power of 2, returns -1 if not.
|
||||||
*/
|
*/
|
||||||
long RingBuffer_Init(RingBuffer * rbuf, long numBytes, void *dataPtr)
|
long RingBuffer_Init(RingBuffer * rbuf, long numBytes, void *dataPtr)
|
||||||
{
|
{
|
||||||
if (((numBytes - 1) & numBytes) != 0)
|
if (((numBytes - 1) & numBytes) != 0)
|
||||||
return -1; /* Not Power of two. */
|
return -1; /* Not Power of two. */
|
||||||
rbuf->bufferSize = numBytes;
|
rbuf->bufferSize = numBytes;
|
||||||
rbuf->buffer = (char *) dataPtr;
|
rbuf->buffer = (char *) dataPtr;
|
||||||
RingBuffer_Flush(rbuf);
|
RingBuffer_Flush(rbuf);
|
||||||
rbuf->bigMask = (numBytes * 2) - 1;
|
rbuf->bigMask = (numBytes * 2) - 1;
|
||||||
rbuf->smallMask = (numBytes) - 1;
|
rbuf->smallMask = (numBytes) - 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
** Return number of bytes available for reading. */
|
|
||||||
long RingBuffer_GetReadAvailable(RingBuffer * rbuf)
|
|
||||||
{
|
|
||||||
return ((rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
/***************************************************************************
|
** Return number of bytes available for reading. */
|
||||||
** Return number of bytes available for writing. */
|
long RingBuffer_GetReadAvailable(RingBuffer * rbuf)
|
||||||
long RingBuffer_GetWriteAvailable(RingBuffer * rbuf)
|
|
||||||
{
|
{
|
||||||
return (rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf));
|
return ((rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
** Clear buffer. Should only be called when buffer is NOT being read. */
|
|
||||||
void RingBuffer_Flush(RingBuffer * rbuf)
|
|
||||||
{
|
|
||||||
rbuf->writeIndex = rbuf->readIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
** Get address of region(s) to which we can write data.
|
** Return number of bytes available for writing. */
|
||||||
** If the region is contiguous, size2 will be zero.
|
long RingBuffer_GetWriteAvailable(RingBuffer * rbuf)
|
||||||
** If non-contiguous, size2 will be the size of second region.
|
|
||||||
** Returns room available to be written or numBytes, whichever is smaller.
|
|
||||||
*/
|
|
||||||
long RingBuffer_GetWriteRegions(RingBuffer * rbuf, long numBytes,
void **dataPtr1, long *sizePtr1,
void **dataPtr2,
|
|
||||||
long *sizePtr2)
|
|
||||||
{
|
{
|
||||||
long index;
|
return (rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf));
|
||||||
long available = RingBuffer_GetWriteAvailable(rbuf);
|
}
|
||||||
if (numBytes > available)
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** Clear buffer. Should only be called when buffer is NOT being read. */
|
||||||
|
void RingBuffer_Flush(RingBuffer * rbuf)
|
||||||
|
{
|
||||||
|
rbuf->writeIndex = rbuf->readIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** Get address of region(s) to which we can write data.
|
||||||
|
** If the region is contiguous, size2 will be zero.
|
||||||
|
** If non-contiguous, size2 will be the size of second region.
|
||||||
|
** Returns room available to be written or numBytes, whichever is smaller.
|
||||||
|
*/
|
||||||
|
long RingBuffer_GetWriteRegions(RingBuffer * rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2,
|
||||||
|
long *sizePtr2)
|
||||||
|
{
|
||||||
|
long index;
|
||||||
|
long available = RingBuffer_GetWriteAvailable(rbuf);
|
||||||
|
if (numBytes > available)
|
||||||
numBytes = available;
|
numBytes = available;
|
||||||
|
|
||||||
/* Check to see if write is not contiguous. */
|
/* Check to see if write is not contiguous. */
|
||||||
index = rbuf->writeIndex & rbuf->smallMask;
|
index = rbuf->writeIndex & rbuf->smallMask;
|
||||||
if ((index + numBytes) > rbuf->bufferSize)
|
if ((index + numBytes) > rbuf->bufferSize)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Write data in two blocks that wrap the buffer. */
|
/* Write data in two blocks that wrap the buffer. */
|
||||||
long firstHalf = rbuf->bufferSize - index;
|
long firstHalf = rbuf->bufferSize - index;
|
||||||
*dataPtr1 = &rbuf->buffer[index];
|
*dataPtr1 = &rbuf->buffer[index];
|
||||||
*sizePtr1 = firstHalf;
|
*sizePtr1 = firstHalf;
|
||||||
*dataPtr2 = &rbuf->buffer[0];
|
*dataPtr2 = &rbuf->buffer[0];
|
||||||
*sizePtr2 = numBytes - firstHalf;
|
*sizePtr2 = numBytes - firstHalf;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*dataPtr1 = &rbuf->buffer[index];
|
*dataPtr1 = &rbuf->buffer[index];
|
||||||
*sizePtr1 = numBytes;
|
*sizePtr1 = numBytes;
|
||||||
*dataPtr2 = NULL;
|
*dataPtr2 = NULL;
|
||||||
*sizePtr2 = 0;
|
*sizePtr2 = 0;
|
||||||
}
|
}
|
||||||
return numBytes;
|
return numBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
*/
|
|
||||||
long RingBuffer_AdvanceWriteIndex(RingBuffer * rbuf, long numBytes)
|
|
||||||
{
|
|
||||||
return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
/***************************************************************************
|
*/
|
||||||
** Get address of region(s) from which we can read data.
|
long RingBuffer_AdvanceWriteIndex(RingBuffer * rbuf, long numBytes)
|
||||||
** If the region is contiguous, size2 will be zero.
|
|
||||||
** If non-contiguous, size2 will be the size of second region.
|
|
||||||
** Returns room available to be written or numBytes, whichever is smaller.
|
|
||||||
*/
|
|
||||||
long RingBuffer_GetReadRegions(RingBuffer * rbuf, long numBytes,
void **dataPtr1, long *sizePtr1,
void **dataPtr2,
|
|
||||||
long *sizePtr2)
|
|
||||||
{
|
{
|
||||||
long index;
|
return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;
|
||||||
long available = RingBuffer_GetReadAvailable(rbuf);
|
}
|
||||||
if (numBytes > available)
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** Get address of region(s) from which we can read data.
|
||||||
|
** If the region is contiguous, size2 will be zero.
|
||||||
|
** If non-contiguous, size2 will be the size of second region.
|
||||||
|
** Returns room available to be written or numBytes, whichever is smaller.
|
||||||
|
*/
|
||||||
|
long RingBuffer_GetReadRegions(RingBuffer * rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2,
|
||||||
|
long *sizePtr2)
|
||||||
|
{
|
||||||
|
long index;
|
||||||
|
long available = RingBuffer_GetReadAvailable(rbuf);
|
||||||
|
if (numBytes > available)
|
||||||
numBytes = available;
|
numBytes = available;
|
||||||
|
|
||||||
/* Check to see if read is not contiguous. */
|
/* Check to see if read is not contiguous. */
|
||||||
index = rbuf->readIndex & rbuf->smallMask;
|
index = rbuf->readIndex & rbuf->smallMask;
|
||||||
if ((index + numBytes) > rbuf->bufferSize)
|
if ((index + numBytes) > rbuf->bufferSize)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Write data in two blocks that wrap the buffer. */
|
/* Write data in two blocks that wrap the buffer. */
|
||||||
long firstHalf = rbuf->bufferSize - index;
|
long firstHalf = rbuf->bufferSize - index;
|
||||||
*dataPtr1 = &rbuf->buffer[index];
|
*dataPtr1 = &rbuf->buffer[index];
|
||||||
*sizePtr1 = firstHalf;
|
*sizePtr1 = firstHalf;
|
||||||
*dataPtr2 = &rbuf->buffer[0];
|
*dataPtr2 = &rbuf->buffer[0];
|
||||||
*sizePtr2 = numBytes - firstHalf;
|
*sizePtr2 = numBytes - firstHalf;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*dataPtr1 = &rbuf->buffer[index];
|
*dataPtr1 = &rbuf->buffer[index];
|
||||||
*sizePtr1 = numBytes;
|
*sizePtr1 = numBytes;
|
||||||
*dataPtr2 = NULL;
|
*dataPtr2 = NULL;
|
||||||
*sizePtr2 = 0;
|
*sizePtr2 = 0;
|
||||||
}
|
}
|
||||||
return numBytes;
|
return numBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
*/
|
|
||||||
long RingBuffer_AdvanceReadIndex(RingBuffer * rbuf, long numBytes)
|
|
||||||
{
|
|
||||||
return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
/***************************************************************************
|
*/
|
||||||
** Return bytes written. */
|
long RingBuffer_AdvanceReadIndex(RingBuffer * rbuf, long numBytes)
|
||||||
long RingBuffer_Write(RingBuffer * rbuf, void *data, long numBytes)
|
|
||||||
{
|
{
|
||||||
long size1, size2, numWritten;
|
return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;
|
||||||
void *data1, *data2;
|
}
|
||||||
numWritten = RingBuffer_GetWriteRegions(rbuf, numBytes, &data1, &size1, &data2, &size2);
|
|
||||||
if (size2 > 0)
|
|
||||||
{
|
/***************************************************************************
|
||||||
memcpy(data1, data, size1);
|
** Return bytes written. */
|
||||||
data = ((char *) data) + size1;
|
long RingBuffer_Write(RingBuffer * rbuf, void *data, long numBytes)
|
||||||
memcpy(data2, data, size2);
|
{
|
||||||
}
|
long size1, size2, numWritten;
|
||||||
|
void *data1, *data2;
|
||||||
|
numWritten = RingBuffer_GetWriteRegions(rbuf, numBytes, &data1, &size1, &data2, &size2);
|
||||||
|
if (size2 > 0)
|
||||||
|
{
|
||||||
|
memcpy(data1, data, size1);
|
||||||
|
data = ((char *) data) + size1;
|
||||||
|
memcpy(data2, data, size2);
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy(data1, data, size1);
|
memcpy(data1, data, size1);
|
||||||
}
|
}
|
||||||
RingBuffer_AdvanceWriteIndex(rbuf, numWritten);
|
RingBuffer_AdvanceWriteIndex(rbuf, numWritten);
|
||||||
return numWritten;
|
return numWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
** Return bytes read. */
|
** Return bytes read. */
|
||||||
long RingBuffer_Read(RingBuffer * rbuf, void *data, long numBytes)
|
long RingBuffer_Read(RingBuffer * rbuf, void *data, long numBytes)
|
||||||
{
|
{
|
||||||
long size1, size2, numRead;
|
long size1, size2, numRead;
|
||||||
void *data1, *data2;
|
void *data1, *data2;
|
||||||
numRead = RingBuffer_GetReadRegions(rbuf, numBytes, &data1, &size1, &data2, &size2);
|
numRead = RingBuffer_GetReadRegions(rbuf, numBytes, &data1, &size1, &data2, &size2);
|
||||||
if (size2 > 0)
|
if (size2 > 0)
|
||||||
{
|
{
|
||||||
memcpy(data, data1, size1);
|
memcpy(data, data1, size1);
|
||||||
data = ((char *) data) + size1;
|
data = ((char *) data) + size1;
|
||||||
memcpy(data, data2, size2);
|
memcpy(data, data2, size2);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy(data, data1, size1);
|
memcpy(data, data1, size1);
|
||||||
}
|
}
|
||||||
RingBuffer_AdvanceReadIndex(rbuf, numRead);
|
RingBuffer_AdvanceReadIndex(rbuf, numRead);
|
||||||
return numRead;
|
return numRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,103 +1,103 @@
|
||||||
#ifndef _RINGBUFFER_H
|
#ifndef _RINGBUFFER_H
|
||||||
#define _RINGBUFFER_H
|
#define _RINGBUFFER_H
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Id: ringbuffer.h,v 1.1.1.1.4.2 2003/04/28 17:45:34 philburk Exp $
|
* $Id: ringbuffer.h,v 1.1.1.1.4.2 2003/04/28 17:45:34 philburk Exp $
|
||||||
* ringbuffer.h
|
* ringbuffer.h
|
||||||
* Ring Buffer utility..
|
* Ring Buffer utility..
|
||||||
*
|
*
|
||||||
* Author: Phil Burk, http://www.softsynth.com
|
* Author: Phil Burk, http://www.softsynth.com
|
||||||
*
|
*
|
||||||
* This program is distributed with the PortAudio Portable Audio Library.
|
* This program is distributed with the PortAudio Portable Audio Library.
|
||||||
* For more information see: http://www.audiomulch.com/portaudio/
|
* For more information see: http://www.audiomulch.com/portaudio/
|
||||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files
|
* a copy of this software and associated documentation files
|
||||||
* (the "Software"), to deal in the Software without restriction,
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
* including without limitation the rights to use, copy, modify, merge,
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
* and to permit persons to whom the Software is furnished to do so,
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
* subject to the following conditions:
|
* subject to the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be
|
* The above copyright notice and this permission notice shall be
|
||||||
* included in all copies or substantial portions of the Software.
|
* included in all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* Any person wishing to distribute modifications to the Software is
|
* Any person wishing to distribute modifications to the Software is
|
||||||
* requested to send the modifications to the original developer so that
|
* requested to send the modifications to the original developer so that
|
||||||
* they can be incorporated into the canonical version.
|
* they can be incorporated into the canonical version.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#define PortAudioStream PaStream
|
#define PortAudioStream PaStream
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */
|
long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */
|
||||||
/* These are declared volatile because they are written by a different thread than the reader. */
|
/* These are declared volatile because they are written by a different thread than the reader. */
|
||||||
volatile long writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */
|
volatile long writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */
|
||||||
volatile long readIndex; /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */
|
volatile long readIndex; /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */
|
||||||
long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */
|
long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */
|
||||||
long smallMask; /* Used for fitting indices to buffer. */
|
long smallMask; /* Used for fitting indices to buffer. */
|
||||||
char *buffer;
|
char *buffer;
|
||||||
}
|
}
|
||||||
RingBuffer;
|
RingBuffer;
|
||||||
/*
|
/*
|
||||||
* Initialize Ring Buffer.
|
* Initialize Ring Buffer.
|
||||||
* numBytes must be power of 2, returns -1 if not.
|
* numBytes must be power of 2, returns -1 if not.
|
||||||
*/
|
*/
|
||||||
long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );
|
long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );
|
||||||
|
|
||||||
/* Clear buffer. Should only be called when buffer is NOT being read. */
|
/* Clear buffer. Should only be called when buffer is NOT being read. */
|
||||||
void RingBuffer_Flush( RingBuffer *rbuf );
|
void RingBuffer_Flush( RingBuffer *rbuf );
|
||||||
|
|
||||||
/* Return number of bytes available for writing. */
|
/* Return number of bytes available for writing. */
|
||||||
long RingBuffer_GetWriteAvailable( RingBuffer *rbuf );
|
long RingBuffer_GetWriteAvailable( RingBuffer *rbuf );
|
||||||
/* Return number of bytes available for read. */
|
/* Return number of bytes available for read. */
|
||||||
long RingBuffer_GetReadAvailable( RingBuffer *rbuf );
|
long RingBuffer_GetReadAvailable( RingBuffer *rbuf );
|
||||||
/* Return bytes written. */
|
/* Return bytes written. */
|
||||||
long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes );
|
long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes );
|
||||||
/* Return bytes read. */
|
/* Return bytes read. */
|
||||||
long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes );
|
long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes );
|
||||||
|
|
||||||
/* Get address of region(s) to which we can write data.
|
/* Get address of region(s) to which we can write data.
|
||||||
** If the region is contiguous, size2 will be zero.
|
** If the region is contiguous, size2 will be zero.
|
||||||
** If non-contiguous, size2 will be the size of second region.
|
** If non-contiguous, size2 will be the size of second region.
|
||||||
** Returns room available to be written or numBytes, whichever is smaller.
|
** Returns room available to be written or numBytes, whichever is smaller.
|
||||||
*/
|
*/
|
||||||
long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
|
long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
|
||||||
void **dataPtr1, long *sizePtr1,
|
void **dataPtr1, long *sizePtr1,
|
||||||
void **dataPtr2, long *sizePtr2 );
|
void **dataPtr2, long *sizePtr2 );
|
||||||
long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes );
|
long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes );
|
||||||
|
|
||||||
/* Get address of region(s) from which we can read data.
|
/* Get address of region(s) from which we can read data.
|
||||||
** If the region is contiguous, size2 will be zero.
|
** If the region is contiguous, size2 will be zero.
|
||||||
** If non-contiguous, size2 will be the size of second region.
|
** If non-contiguous, size2 will be the size of second region.
|
||||||
** Returns room available to be read or numBytes, whichever is smaller.
|
** Returns room available to be read or numBytes, whichever is smaller.
|
||||||
*/
|
*/
|
||||||
long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
|
long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
|
||||||
void **dataPtr1, long *sizePtr1,
|
void **dataPtr1, long *sizePtr1,
|
||||||
void **dataPtr2, long *sizePtr2 );
|
void **dataPtr2, long *sizePtr2 );
|
||||||
|
|
||||||
long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );
|
long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#endif /* _RINGBUFFER_H */
|
#endif /* _RINGBUFFER_H */
|
||||||
|
|
Loading…
Reference in New Issue