Merge branch 'ticket_229' into 'master'

Fix assert when reading or writing with non-power of 2 channels.

fixed #229

Merged-on: https://assembla.com/code/portaudio/git/merge_requests/3299213
This commit is contained in:
Phil Burk 2016-05-29 19:22:24 +00:00
commit e111b3a269
6 changed files with 180 additions and 178 deletions

View file

@ -33,13 +33,13 @@
*/
/*
* The text above constitutes the entire PortAudio license; however,
* The text above constitutes the entire PortAudio license; however,
* the PortAudio community also makes the following non-binding requests:
*
* Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the
* they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the
* license above.
*/
@ -49,56 +49,40 @@
#include "portaudio.h"
/* #define SAMPLE_RATE (17932) // Test failure to open with this value. */
#define SAMPLE_RATE (44100)
#define FRAMES_PER_BUFFER (1024)
#define NUM_CHANNELS (2)
#define NUM_SECONDS (15)
#define SAMPLE_RATE (44100)
#define FRAMES_PER_BUFFER (512)
#define NUM_SECONDS (10)
/* #define DITHER_FLAG (paDitherOff) */
#define DITHER_FLAG (0) /**/
/* @todo Underflow and overflow is disabled until we fix priming of blocking write. */
#define CHECK_OVERFLOW (0)
#define CHECK_UNDERFLOW (0)
#define DITHER_FLAG (0)
/* Select sample format. */
#if 0
#if 1
#define PA_SAMPLE_TYPE paFloat32
#define SAMPLE_SIZE (4)
#define SAMPLE_SILENCE (0.0f)
#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
#define PRINTF_S_FORMAT "%.8f"
#elif 0
#define PA_SAMPLE_TYPE paInt16
#define SAMPLE_SIZE (2)
#define SAMPLE_SILENCE (0)
#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
#define PRINTF_S_FORMAT "%d"
#elif 1
#elif 0
#define PA_SAMPLE_TYPE paInt24
#define SAMPLE_SIZE (3)
#define SAMPLE_SILENCE (0)
#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
#define PRINTF_S_FORMAT "%d"
#elif 0
#define PA_SAMPLE_TYPE paInt8
#define SAMPLE_SIZE (1)
#define SAMPLE_SILENCE (0)
#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
#define PRINTF_S_FORMAT "%d"
#else
#define PA_SAMPLE_TYPE paUInt8
#define SAMPLE_SIZE (1)
#define SAMPLE_SILENCE (128)
#define CLEAR( a ) { \
int i; \
for( i=0; i<FRAMES_PER_BUFFER*NUM_CHANNELS; i++ ) \
((unsigned char *)a)[i] = (SAMPLE_SILENCE); \
}
#define PRINTF_S_FORMAT "%d"
#endif
/*******************************************************************/
int main(void);
int main(void)
@ -106,46 +90,50 @@ int main(void)
PaStreamParameters inputParameters, outputParameters;
PaStream *stream = NULL;
PaError err;
char *sampleBlock;
const PaDeviceInfo* inputInfo;
const PaDeviceInfo* outputInfo;
char *sampleBlock = NULL;
int i;
int numBytes;
printf("patest_read_write_wire.c\n"); fflush(stdout);
numBytes = FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ;
sampleBlock = (char *) malloc( numBytes );
if( sampleBlock == NULL )
{
printf("Could not allocate record array.\n");
exit(1);
}
CLEAR( sampleBlock );
printf("patest_read_write_wire.c\n"); fflush(stdout);
printf("sizeof(int) = %lu\n", sizeof(int)); fflush(stdout);
printf("sizeof(long) = %lu\n", sizeof(long)); fflush(stdout);
err = Pa_Initialize();
if( err != paNoError ) goto error;
if( err != paNoError ) goto error2;
inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
printf( "Input device # %d.\n", inputParameters.device );
printf( "Input LL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency );
printf( "Input HL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency );
inputParameters.channelCount = NUM_CHANNELS;
inputParameters.sampleFormat = PA_SAMPLE_TYPE;
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ;
inputParameters.hostApiSpecificStreamInfo = NULL;
inputInfo = Pa_GetDeviceInfo( inputParameters.device );
printf( " Name: %s\n", inputInfo->name );
printf( " LL: %g s\n", inputInfo->defaultLowInputLatency );
printf( " HL: %g s\n", inputInfo->defaultHighInputLatency );
outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
printf( "Output device # %d.\n", outputParameters.device );
printf( "Output LL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency );
printf( "Output HL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency );
outputParameters.channelCount = NUM_CHANNELS;
outputInfo = Pa_GetDeviceInfo( outputParameters.device );
printf( " Name: %s\n", outputInfo->name );
printf( " LL: %g s\n", outputInfo->defaultLowOutputLatency );
printf( " HL: %g s\n", outputInfo->defaultHighOutputLatency );
int numChannels = inputInfo->maxInputChannels < outputInfo->maxOutputChannels
? inputInfo->maxInputChannels : outputInfo->maxOutputChannels;
printf( "Num channels = %d.\n", numChannels );
inputParameters.channelCount = numChannels;
inputParameters.sampleFormat = PA_SAMPLE_TYPE;
inputParameters.suggestedLatency = inputInfo->defaultHighInputLatency ;
inputParameters.hostApiSpecificStreamInfo = NULL;
outputParameters.channelCount = numChannels;
outputParameters.sampleFormat = PA_SAMPLE_TYPE;
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
outputParameters.suggestedLatency = outputInfo->defaultHighOutputLatency;
outputParameters.hostApiSpecificStreamInfo = NULL;
/* -- setup -- */
err = Pa_OpenStream(
err = Pa_OpenStream(
&stream,
&inputParameters,
&outputParameters,
@ -154,46 +142,41 @@ int main(void)
paClipOff, /* we won't output out of range samples so don't bother clipping them */
NULL, /* no callback, use blocking API */
NULL ); /* no callback, so no callback userData */
if( err != paNoError ) goto error;
if( err != paNoError ) goto error2;
numBytes = FRAMES_PER_BUFFER * numChannels * SAMPLE_SIZE ;
sampleBlock = (char *) malloc( numBytes );
if( sampleBlock == NULL )
{
printf("Could not allocate record array.\n");
goto error1;
}
memset( sampleBlock, SAMPLE_SILENCE, numBytes );
err = Pa_StartStream( stream );
if( err != paNoError ) goto error;
if( err != paNoError ) goto error1;
printf("Wire on. Will run %d seconds.\n", NUM_SECONDS); fflush(stdout);
for( i=0; i<(NUM_SECONDS*SAMPLE_RATE)/FRAMES_PER_BUFFER; ++i )
{
err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER );
if( err && CHECK_UNDERFLOW ) goto xrun;
err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER );
if( err && CHECK_OVERFLOW ) goto xrun;
// You may get underruns or overruns if the output is not primed by PortAudio.
err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER );
if( err ) goto xrun;
err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER );
if( err ) goto xrun;
}
printf("Wire off.\n"); fflush(stdout);
err = Pa_StopStream( stream );
if( err != paNoError ) goto error;
if( err != paNoError ) goto error1;
CLEAR( sampleBlock );
/*
err = Pa_StartStream( stream );
if( err != paNoError ) goto error;
printf("Wire on. Interrupt to stop.\n"); fflush(stdout);
while( 1 )
{
err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER );
if( err ) goto xrun;
err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER );
if( err ) goto xrun;
}
err = Pa_StopStream( stream );
if( err != paNoError ) goto error;
Pa_CloseStream( stream );
*/
free( sampleBlock );
Pa_Terminate();
return 0;
xrun:
printf("err = %d\n", err); fflush(stdout);
if( stream ) {
Pa_AbortStream( stream );
Pa_CloseStream( stream );
@ -205,13 +188,13 @@ xrun:
if( err & paOutputUnderflow )
fprintf( stderr, "Output Underflow.\n" );
return -2;
error:
error1:
free( sampleBlock );
error2:
if( stream ) {
Pa_AbortStream( stream );
Pa_CloseStream( stream );
}
free( sampleBlock );
Pa_Terminate();
fprintf( stderr, "An error occured while using the portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err );

View file

@ -1921,14 +1921,13 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
/*
* If input and output devs are different or we are doing SR conversion,
* we also need a
* ring buffer to store inpt data while waiting for output
* data.
* we also need a ring buffer to store input data while waiting for
* output data.
*/
if( (stream->outputUnit && (stream->inputUnit != stream->outputUnit))
|| stream->inputSRConverter )
{
/* May want the ringSize ot initial position in
/* May want the ringSize or initial position in
ring buffer to depend somewhat on sample rate change */
void *data;
@ -1951,7 +1950,15 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
}
/* now we can initialize the ring buffer */
PaUtil_InitializeRingBuffer( &stream->inputRingBuffer, szfl*inputParameters->channelCount, ringSize, data ) ;
result = PaUtil_InitializeRingBuffer( &stream->inputRingBuffer, szfl*inputParameters->channelCount, ringSize, data );
if( result != 0 )
{
/* The only reason this should fail is if ringSize is not a power of 2, which we do not anticipate happening. */
result = paUnanticipatedHostError;
free(data);
goto error;
}
/* advance the read point a little, so we are reading from the
middle of the buffer */
if( stream->outputUnit )
@ -1973,12 +1980,11 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
stream->outputFramesPerBuffer,
sampleRate );
result = initializeBlioRingBuffers( &stream->blio,
inputParameters?inputParameters->sampleFormat:0 ,
outputParameters?outputParameters->sampleFormat:0 ,
MAX(stream->inputFramesPerBuffer,stream->outputFramesPerBuffer),
inputParameters ? inputParameters->sampleFormat : 0,
outputParameters ? outputParameters->sampleFormat : 0,
ringSize,
inputParameters?inputChannelCount:0 ,
outputParameters?outputChannelCount:0 ) ;
inputParameters ? inputChannelCount : 0,
outputParameters ? outputChannelCount : 0 ) ;
if( result != paNoError )
goto error;

View file

@ -108,14 +108,16 @@ static size_t computeSampleSizeFromFormatPow2( PaSampleFormat format )
*
*/
/* This should be called with the relevant info when initializing a stream for
callback. */
/**
* This should be called with the relevant info when initializing a stream for callback.
*
* @param ringBufferSizeInFrames must be a power of 2
*/
PaError initializeBlioRingBuffers(
PaMacBlio *blio,
PaSampleFormat inputSampleFormat,
PaSampleFormat outputSampleFormat,
size_t framesPerBuffer,
long ringBufferSize,
long ringBufferSizeInFrames,
int inChan,
int outChan )
{
@ -126,20 +128,19 @@ PaError initializeBlioRingBuffers(
/* zeroify things */
bzero( blio, sizeof( PaMacBlio ) );
/* this is redundant, but the buffers are used to check
if the bufffers have been initialized, so we do it explicitly. */
if the buffers have been initialized, so we do it explicitly. */
blio->inputRingBuffer.buffer = NULL;
blio->outputRingBuffer.buffer = NULL;
/* initialize simple data */
blio->ringBufferFrames = ringBufferSize;
blio->ringBufferFrames = ringBufferSizeInFrames;
blio->inputSampleFormat = inputSampleFormat;
blio->inputSampleSizeActual = computeSampleSizeFromFormat(inputSampleFormat);
blio->inputSampleSizePow2 = computeSampleSizeFromFormatPow2(inputSampleFormat);
blio->inputSampleSizePow2 = computeSampleSizeFromFormatPow2(inputSampleFormat); // FIXME: WHY?
blio->outputSampleFormat = outputSampleFormat;
blio->outputSampleSizeActual = computeSampleSizeFromFormat(outputSampleFormat);
blio->outputSampleSizePow2 = computeSampleSizeFromFormatPow2(outputSampleFormat);
blio->framesPerBuffer = framesPerBuffer;
blio->inChan = inChan;
blio->outChan = outChan;
blio->statusFlags = 0;
@ -163,7 +164,7 @@ PaError initializeBlioRingBuffers(
result = UNIX_ERR( pthread_cond_init( &(blio->outputCond), NULL ) );
#endif
if( inChan ) {
data = calloc( ringBufferSize, blio->inputSampleSizePow2*inChan );
data = calloc( ringBufferSizeInFrames, blio->inputSampleSizePow2 * inChan );
if( !data )
{
result = paInsufficientMemory;
@ -172,12 +173,13 @@ PaError initializeBlioRingBuffers(
err = PaUtil_InitializeRingBuffer(
&blio->inputRingBuffer,
1, ringBufferSize*blio->inputSampleSizePow2*inChan,
blio->inputSampleSizePow2 * inChan,
ringBufferSizeInFrames,
data );
assert( !err );
}
if( outChan ) {
data = calloc( ringBufferSize, blio->outputSampleSizePow2*outChan );
data = calloc( ringBufferSizeInFrames, blio->outputSampleSizePow2 * outChan );
if( !data )
{
result = paInsufficientMemory;
@ -186,7 +188,8 @@ PaError initializeBlioRingBuffers(
err = PaUtil_InitializeRingBuffer(
&blio->outputRingBuffer,
1, ringBufferSize*blio->outputSampleSizePow2*outChan,
blio->outputSampleSizePow2 * outChan,
ringBufferSizeInFrames,
data );
assert( !err );
}
@ -266,12 +269,11 @@ PaError resetBlioRingBuffers( PaMacBlio *blio )
#endif
blio->statusFlags = 0;
if( blio->outputRingBuffer.buffer ) {
PaUtil_FlushRingBuffer( &blio->outputRingBuffer );
bzero( blio->outputRingBuffer.buffer,
blio->outputRingBuffer.bufferSize );
/* Advance buffer */
PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->ringBufferFrames*blio->outputSampleSizeActual*blio->outChan );
//PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->outputRingBuffer.bufferSize );
PaUtil_FlushRingBuffer( &blio->outputRingBuffer );
/* Fill the buffer with zeros. */
bzero( blio->outputRingBuffer.buffer,
blio->outputRingBuffer.bufferSize * blio->outputRingBuffer.elementSizeBytes );
PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->ringBufferFrames );
/* Update isOutputFull. */
#ifdef PA_MAC__BLIO_MUTEX
@ -280,16 +282,14 @@ PaError resetBlioRingBuffers( PaMacBlio *blio )
goto error;
#endif
/*
printf( "------%d\n" , blio->framesPerBuffer );
printf( "------%d\n" , blio->outChan );
printf( "------%d\n" , blio->outputSampleSize );
printf( "------%d\n" , blio->framesPerBuffer*blio->outChan*blio->outputSampleSize );
*/
}
if( blio->inputRingBuffer.buffer ) {
PaUtil_FlushRingBuffer( &blio->inputRingBuffer );
bzero( blio->inputRingBuffer.buffer,
blio->inputRingBuffer.bufferSize );
blio->inputRingBuffer.bufferSize * blio->inputRingBuffer.elementSizeBytes );
/* Update isInputEmpty. */
#ifdef PA_MAC__BLIO_MUTEX
result = blioSetIsInputEmpty( blio, true );
@ -344,30 +344,32 @@ int BlioCallback( const void *input, void *output, unsigned long frameCount,
void *userData )
{
PaMacBlio *blio = (PaMacBlio*)userData;
long avail;
long toRead;
long toWrite;
long read;
long written;
ring_buffer_size_t framesAvailable;
ring_buffer_size_t framesToTransfer;
ring_buffer_size_t framesTransferred;
/* set flags returned by OS: */
OSAtomicOr32( statusFlags, &blio->statusFlags ) ;
/* --- Handle Input Buffer --- */
if( blio->inChan ) {
avail = PaUtil_GetRingBufferWriteAvailable( &blio->inputRingBuffer );
framesAvailable = PaUtil_GetRingBufferWriteAvailable( &blio->inputRingBuffer );
/* check for underflow */
if( avail < frameCount * blio->inputSampleSizeActual * blio->inChan )
if( framesAvailable < frameCount )
{
OSAtomicOr32( paInputOverflow, &blio->statusFlags );
OSAtomicOr32( paInputOverflow, &blio->statusFlags );
framesToTransfer = framesAvailable;
}
else
{
framesToTransfer = (ring_buffer_size_t)frameCount;
}
toRead = MIN( avail, frameCount * blio->inputSampleSizeActual * blio->inChan );
/* copy the data */
/* Copy the data from the audio input to the application ring buffer. */
/*printf( "reading %d\n", toRead );*/
read = PaUtil_WriteRingBuffer( &blio->inputRingBuffer, input, toRead );
assert( toRead == read );
framesTransferred = PaUtil_WriteRingBuffer( &blio->inputRingBuffer, input, framesToTransfer );
assert( framesToTransfer == framesTransferred );
#ifdef PA_MAC__BLIO_MUTEX
/* Priority inversion. See notes below. */
blioSetIsInputEmpty( blio, false );
@ -377,21 +379,31 @@ int BlioCallback( const void *input, void *output, unsigned long frameCount,
/* --- Handle Output Buffer --- */
if( blio->outChan ) {
avail = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer );
framesAvailable = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer );
/* check for underflow */
if( avail < frameCount * blio->outputSampleSizeActual * blio->outChan )
OSAtomicOr32( paOutputUnderflow, &blio->statusFlags );
if( framesAvailable < frameCount )
{
/* zero out the end of the output buffer that we do not have data for */
framesToTransfer = framesAvailable;
toWrite = MIN( avail, frameCount * blio->outputSampleSizeActual * blio->outChan );
size_t bytesPerFrame = blio->outputSampleSizeActual * blio->outChan;
size_t offsetInBytes = framesToTransfer * bytesPerFrame;
size_t countInBytes = (frameCount - framesToTransfer) * bytesPerFrame;
bzero( ((char *)output) + offsetInBytes, countInBytes );
OSAtomicOr32( paOutputUnderflow, &blio->statusFlags );
framesToTransfer = framesAvailable;
}
else
{
framesToTransfer = (ring_buffer_size_t)frameCount;
}
if( toWrite != frameCount * blio->outputSampleSizeActual * blio->outChan )
bzero( ((char *)output)+toWrite,
frameCount * blio->outputSampleSizeActual * blio->outChan - toWrite );
/* copy the data */
/*printf( "writing %d\n", toWrite );*/
written = PaUtil_ReadRingBuffer( &blio->outputRingBuffer, output, toWrite );
assert( toWrite == written );
framesTransferred = PaUtil_ReadRingBuffer( &blio->outputRingBuffer, output, framesToTransfer );
assert( framesToTransfer == framesTransferred );
#ifdef PA_MAC__BLIO_MUTEX
/* We have a priority inversion here. However, we will only have to
wait if this was true and is now false, which means we've got
@ -406,24 +418,25 @@ int BlioCallback( const void *input, void *output, unsigned long frameCount,
PaError ReadStream( PaStream* stream,
void *buffer,
unsigned long frames )
unsigned long framesRequested )
{
PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
char *cbuf = (char *) buffer;
PaError ret = paNoError;
VVDBUG(("ReadStream()\n"));
while( frames > 0 ) {
long avail;
long toRead;
while( framesRequested > 0 ) {
ring_buffer_size_t framesAvailable;
ring_buffer_size_t framesToTransfer;
ring_buffer_size_t framesTransferred;
do {
avail = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer );
framesAvailable = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer );
/*
printf( "Read Buffer is %%%g full: %ld of %ld.\n",
100 * (float)avail / (float) blio->inputRingBuffer.bufferSize,
avail, blio->inputRingBuffer.bufferSize );
framesAvailable, blio->inputRingBuffer.bufferSize );
*/
if( avail == 0 ) {
if( framesAvailable == 0 ) {
#ifdef PA_MAC_BLIO_MUTEX
/**block when empty*/
ret = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) );
@ -441,14 +454,13 @@ PaError ReadStream( PaStream* stream,
Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
#endif
}
} while( avail == 0 );
toRead = MIN( avail, frames * blio->inputSampleSizeActual * blio->inChan );
toRead -= toRead % blio->inputSampleSizeActual * blio->inChan ;
PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, toRead );
cbuf += toRead;
frames -= toRead / ( blio->inputSampleSizeActual * blio->inChan );
} while( framesAvailable == 0 );
framesToTransfer = MIN( framesAvailable, framesRequested );
framesTransferred = PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, framesToTransfer );
cbuf += framesTransferred * blio->inputSampleSizeActual * blio->inChan;
framesRequested -= framesTransferred;
if( toRead == avail ) {
if( framesToTransfer == framesAvailable ) {
#ifdef PA_MAC_BLIO_MUTEX
/* we just emptied the buffer, so we need to mark it as empty. */
ret = blioSetIsInputEmpty( blio, true );
@ -457,8 +469,10 @@ PaError ReadStream( PaStream* stream,
/* of course, in the meantime, the callback may have put some sats
in, so
so check for that, too, to avoid a race condition. */
/* FIXME - this does not seem to fix any race condition. */
if( PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ) ) {
blioSetIsInputEmpty( blio, false );
/* FIXME - why check? ret has not been set? */
if( ret )
return ret;
}
@ -468,6 +482,7 @@ PaError ReadStream( PaStream* stream,
/* Report either paNoError or paInputOverflowed. */
/* may also want to report other errors, but this is non-standard. */
/* FIXME should not clobber ret, use if(blio->statusFlags & paInputOverflow) */
ret = blio->statusFlags & paInputOverflow;
/* report underflow only once: */
@ -482,25 +497,26 @@ PaError ReadStream( PaStream* stream,
PaError WriteStream( PaStream* stream,
const void *buffer,
unsigned long frames )
unsigned long framesRequested )
{
PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
char *cbuf = (char *) buffer;
PaError ret = paNoError;
VVDBUG(("WriteStream()\n"));
while( frames > 0 ) {
long avail = 0;
long toWrite;
while( framesRequested > 0 ) {
ring_buffer_size_t framesAvailable;
ring_buffer_size_t framesToTransfer;
ring_buffer_size_t framesTransferred;
do {
avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
framesAvailable = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
/*
printf( "Write Buffer is %%%g full: %ld of %ld.\n",
100 - 100 * (float)avail / (float) blio->outputRingBuffer.bufferSize,
avail, blio->outputRingBuffer.bufferSize );
framesAvailable, blio->outputRingBuffer.bufferSize );
*/
if( avail == 0 ) {
if( framesAvailable == 0 ) {
#ifdef PA_MAC_BLIO_MUTEX
/*block while full*/
ret = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) );
@ -518,16 +534,15 @@ PaError WriteStream( PaStream* stream,
Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
#endif
}
} while( avail == 0 );
} while( framesAvailable == 0 );
toWrite = MIN( avail, frames * blio->outputSampleSizeActual * blio->outChan );
toWrite -= toWrite % blio->outputSampleSizeActual * blio->outChan ;
PaUtil_WriteRingBuffer( &blio->outputRingBuffer, (void *)cbuf, toWrite );
cbuf += toWrite;
frames -= toWrite / ( blio->outputSampleSizeActual * blio->outChan );
framesToTransfer = MIN( framesAvailable, framesRequested );
framesTransferred = PaUtil_WriteRingBuffer( &blio->outputRingBuffer, (void *)cbuf, framesToTransfer );
cbuf += framesTransferred * blio->outputSampleSizeActual * blio->outChan;
framesRequested -= framesTransferred;
#ifdef PA_MAC_BLIO_MUTEX
if( toWrite == avail ) {
if( framesToTransfer == framesAvailable ) {
/* we just filled up the buffer, so we need to mark it as filled. */
ret = blioSetIsOutputFull( blio, true );
if( ret )
@ -536,6 +551,7 @@ PaError WriteStream( PaStream* stream,
so check for that, too, to avoid a race condition. */
if( PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ) ) {
blioSetIsOutputFull( blio, false );
/* FIXME remove or review this code, does not fix race, ret not set! */
if( ret )
return ret;
}
@ -545,6 +561,7 @@ PaError WriteStream( PaStream* stream,
/* Report either paNoError or paOutputUnderflowed. */
/* may also want to report other errors, but this is non-standard. */
/* FIXME should not clobber ret, use if(blio->statusFlags & paInputOverflow) */
ret = blio->statusFlags & paOutputUnderflow;
/* report underflow only once: */
@ -562,11 +579,12 @@ PaError WriteStream( PaStream* stream,
void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio )
{
if( blio->outputRingBuffer.buffer ) {
long avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
while( avail != blio->outputRingBuffer.bufferSize ) {
if( avail == 0 )
/* FIXME loop until PaUtil_GetRingBufferReadAvailable==0 */
ring_buffer_size_t framesAvailable = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
while( framesAvailable != blio->outputRingBuffer.bufferSize ) {
if( framesAvailable == 0 )
Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
framesAvailable = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
}
}
}
@ -577,8 +595,7 @@ signed long GetStreamReadAvailable( PaStream* stream )
PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
VVDBUG(("GetStreamReadAvailable()\n"));
return PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer )
/ ( blio->inputSampleSizeActual * blio->inChan );
return PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer );
}
@ -587,7 +604,6 @@ signed long GetStreamWriteAvailable( PaStream* stream )
PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
VVDBUG(("GetStreamWriteAvailable()\n"));
return PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer )
/ ( blio->outputSampleSizeActual * blio->outChan );
return PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
}

View file

@ -64,7 +64,7 @@
#include "pa_mac_core_utilities.h"
/*
* Number of miliseconds to busy wait whil waiting for data in blocking calls.
* Number of milliseconds to busy wait while waiting for data in blocking calls.
*/
#define PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL (5)
/*
@ -79,7 +79,7 @@
typedef struct {
PaUtilRingBuffer inputRingBuffer;
PaUtilRingBuffer outputRingBuffer;
size_t ringBufferFrames;
ring_buffer_size_t ringBufferFrames;
PaSampleFormat inputSampleFormat;
size_t inputSampleSizeActual;
size_t inputSampleSizePow2;
@ -87,8 +87,6 @@ typedef struct {
size_t outputSampleSizeActual;
size_t outputSampleSizePow2;
size_t framesPerBuffer;
int inChan;
int outChan;
@ -117,8 +115,7 @@ PaError initializeBlioRingBuffers(
PaMacBlio *blio,
PaSampleFormat inputSampleFormat,
PaSampleFormat outputSampleFormat,
size_t framesPerBuffer,
long ringBufferSize,
long ringBufferSizeInFrames,
int inChan,
int outChan );
PaError destroyBlioRingBuffers( PaMacBlio *blio );

View file

@ -46,8 +46,8 @@
#include <math.h>
#include "portaudio.h"
#define MAX_SINES (500)
#define MAX_USAGE (0.8)
#define MAX_SINES (2000)
#define MAX_USAGE (0.5)
#define SAMPLE_RATE (44100)
#define FREQ_TO_PHASE_INC(freq) (freq/(float)SAMPLE_RATE)
@ -60,7 +60,7 @@
#endif
#define TWOPI (M_PI * 2.0)
#define TABLE_SIZE (512)
#define TABLE_SIZE (1024)
typedef struct paTestData
{
@ -70,7 +70,7 @@ typedef struct paTestData
}
paTestData;
/* Convert phase between and 1.0 to sine value
/* Convert phase between 0.0 and 1.0 to sine value
* using linear interpolation.
*/
float LookupSine( paTestData *data, float phase );
@ -187,14 +187,14 @@ int main(void)
/* Play an increasing number of sine waves until we hit MAX_USAGE */
do {
data.numSines++;
data.numSines += 10;
Pa_Sleep(200);
load = Pa_GetStreamCpuLoad(stream);
printf("numSines = %d, CPU load = %f\n", data.numSines, load );
fflush(stdout);
} while((load < MAX_USAGE) && (data.numSines < MAX_SINES));
Pa_Sleep(2000); /* Stay for 2 seconds around 80% CPU. */
Pa_Sleep(2000); /* Stay for 2 seconds at max CPU. */
err = Pa_StopStream( stream );
if( err != paNoError )

View file

@ -47,7 +47,7 @@
#include "portaudio.h"
#define SAMPLE_RATE (44100)
#define FRAMES_PER_BUFFER (256)
#define FRAMES_PER_BUFFER (128)
#define FREQ_INCR (300.0 / SAMPLE_RATE)
#define MAX_CHANNELS (64)