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:
commit
e111b3a269
6 changed files with 180 additions and 178 deletions
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue