Commit e2c4edd3 authored by philburk's avatar philburk

Implement the Float32 to UInt8 converters.

The loopback test now passes cleanly for the first time on my PreSonus FireStudio.
Added tests for clip and dither flag combinations to loopback.


git-svn-id: https://subversion.assembla.com/svn/portaudio/portaudio/trunk@1748 0f58301d-fd10-0410-b4af-bbb618454e57
parent 760bdf4c
......@@ -91,7 +91,8 @@ typedef struct TestParameters_s
int maxFrames;
double baseFrequency;
double amplitude;
int flags;
PaStreamFlags streamFlags; // paClipOff, etc
int flags; // PAQA_FLAG_TWO_STREAMS, PAQA_FLAG_USE_BLOCKING_IO
} TestParameters;
typedef struct LoopbackContext_s
......@@ -106,15 +107,19 @@ typedef struct LoopbackContext_s
PaTime streamInfoOutputLatency;
// Measured at runtime.
int callbackCount; // incremented for each callback
int inputBufferCount; // incremented if input buffer not NULL
volatile int callbackCount; // incremented for each callback
volatile int inputBufferCount; // incremented if input buffer not NULL
int inputUnderflowCount;
int inputOverflowCount;
int outputBufferCount; // incremented if output buffer not NULL
volatile int outputBufferCount; // incremented if output buffer not NULL
int outputOverflowCount;
int outputUnderflowCount;
// Measure whether input or output is lagging behind.
volatile int minInputOutputDelta;
volatile int maxInputOutputDelta;
int minFramesPerBuffer;
int maxFramesPerBuffer;
int primingCount;
......@@ -239,7 +244,22 @@ static int RecordAndPlaySinesCallback( const void *inputBuffer, void *outputBuff
}
}
// Measure whether the input or output are lagging behind.
// Don't measure lag at end.
if( !loopbackContext->done )
{
int inputOutputDelta = loopbackContext->inputBufferCount - loopbackContext->outputBufferCount;
if( loopbackContext->maxInputOutputDelta < inputOutputDelta )
{
loopbackContext->maxInputOutputDelta = inputOutputDelta;
}
if( loopbackContext->minInputOutputDelta > inputOutputDelta )
{
loopbackContext->minInputOutputDelta = inputOutputDelta;
}
}
return loopbackContext->done ? paComplete : paContinue;
}
......@@ -350,7 +370,7 @@ int PaQa_RunLoopbackHalfDuplex( LoopbackContext *loopbackContext )
NULL,
test->sampleRate,
test->framesPerBuffer,
paClipOff, /* we won't output out of range samples so don't bother clipping them */
test->streamFlags,
RecordAndPlaySinesCallback,
loopbackContext );
if( err != paNoError ) goto error;
......@@ -360,7 +380,7 @@ int PaQa_RunLoopbackHalfDuplex( LoopbackContext *loopbackContext )
&test->outputParameters,
test->sampleRate,
test->framesPerBuffer,
paClipOff, /* we won't output out of range samples so don't bother clipping them */
test->streamFlags,
RecordAndPlaySinesCallback,
loopbackContext );
if( err != paNoError ) goto error;
......@@ -870,8 +890,9 @@ static int PaQa_SingleLoopBackTest( UserOptions *userOptions, TestParameters *te
{
printf( "OK" );
}
printf( "\n" );
PaQa_TeardownLoopbackContext( &loopbackContext );
if( numBadChannels > 0 )
......@@ -899,6 +920,7 @@ static void PaQa_SetDefaultTestParameters( TestParameters *testParamsPtr, PaDevi
testParamsPtr->framesPerBuffer = DEFAULT_FRAMES_PER_BUFFER;
testParamsPtr->baseFrequency = 200.0;
testParamsPtr->flags = PAQA_FLAG_TWO_STREAMS;
testParamsPtr->streamFlags = paClipOff; /* we won't output out of range samples so don't bother clipping them */
testParamsPtr->inputParameters.device = inputDevice;
testParamsPtr->inputParameters.sampleFormat = paFloat32;
......@@ -1038,18 +1060,27 @@ static int PaQa_AnalyzeLoopbackConnection( UserOptions *userOptions, PaDeviceInd
}
printf("\nTest Sample Formats using Half Duplex IO -----\n" );
testParams.flags = PAQA_FLAG_TWO_STREAMS;
for( iFormat=0; iFormat<numSampleFormats; iFormat++ )
{
int numBadChannels;
PaSampleFormat format = sampleFormats[ iFormat ];
testParams.inputParameters.sampleFormat = format;
testParams.outputParameters.sampleFormat = format;
printf("Sample format = %d = %s\n", (int) format, sampleFormatNames[iFormat] );
numBadChannels = PaQa_SingleLoopBackTest( userOptions, &testParams );
totalBadChannels += numBadChannels;
}
PaQa_SetDefaultTestParameters( &testParams, inputDevice, outputDevice );
testParams.flags = PAQA_FLAG_TWO_STREAMS;
for( int iFlags= 0; iFlags<4; iFlags++ )
{
// Cycle through combinations of flags.
testParams.streamFlags = 0;
if( iFlags & 1 ) testParams.streamFlags |= paClipOff;
if( iFlags & 2 ) testParams.streamFlags |= paDitherOff;
for( iFormat=0; iFormat<numSampleFormats; iFormat++ )
{
int numBadChannels;
PaSampleFormat format = sampleFormats[ iFormat ];
testParams.inputParameters.sampleFormat = format;
testParams.outputParameters.sampleFormat = format;
printf("Sample format = %d = %s, PaStreamFlags = 0x%02X\n", (int) format, sampleFormatNames[iFormat], (unsigned int) testParams.streamFlags );
numBadChannels = PaQa_SingleLoopBackTest( userOptions, &testParams );
totalBadChannels += numBadChannels;
}
}
printf( "\n" );
printf( "****************************************\n");
......@@ -1159,7 +1190,7 @@ int PaQa_CheckForLoopBack( UserOptions *userOptions, PaDeviceIndex inputDevice,
PaQa_OverrideTestParameters( &testParams, userOptions );
testParams.maxFrames = (int) (LOOPBACK_DETECTION_DURATION_SECONDS * testParams.sampleRate);
minAmplitude = testParams.amplitude / 2.0;
minAmplitude = testParams.amplitude / 4.0;
// Check to see if the selected formats are supported.
if( Pa_IsFormatSupported( &testParams.inputParameters, NULL, testParams.sampleRate ) != paFormatIsSupported )
......
......@@ -49,8 +49,7 @@
see: "require clipping for dithering sample conversion functions?"
http://www.portaudio.com/trac/ticket/112
@todo implement the converters marked IMPLEMENT ME: Float32_To_UInt8_Dither,
Float32_To_UInt8_Clip, Float32_To_UInt8_DitherClip, Int32_To_Int24_Dither,
@todo implement the converters marked IMPLEMENT ME: Int32_To_Int24_Dither,
Int32_To_UInt8_Dither, Int24_To_Int16_Dither, Int24_To_Int8_Dither,
Int24_To_UInt8_Dither, Int16_To_Int8_Dither, Int16_To_UInt8_Dither
see: "some conversion functions are not implemented in pa_converters.c"
......@@ -729,8 +728,7 @@ static void Float32_To_Int8_Dither(
{
float *src = (float*)sourceBuffer;
signed char *dest = (signed char*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
while( count-- )
{
float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
......@@ -821,12 +819,15 @@ static void Float32_To_UInt8_Dither(
{
float *src = (float*)sourceBuffer;
unsigned char *dest = (unsigned char*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
while( count-- )
{
/* IMPLEMENT ME */
float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
/* use smaller scaler to prevent overflow when we add the dither */
float dithered = (*src * (126.0f)) + dither;
PaInt32 samp = (PaInt32) dithered;
*dest = (unsigned char) (128 + samp);
src += sourceStride;
dest += destinationStride;
}
......@@ -845,7 +846,9 @@ static void Float32_To_UInt8_Clip(
while( count-- )
{
/* IMPLEMENT ME */
PaInt32 samp = 128 + (PaInt32)(*src * (127.0f));
PA_CLIP_( samp, 0x0000, 0x00FF );
*dest = (unsigned char) samp;
src += sourceStride;
dest += destinationStride;
......@@ -865,7 +868,12 @@ static void Float32_To_UInt8_DitherClip(
while( count-- )
{
/* IMPLEMENT ME */
float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
/* use smaller scaler to prevent overflow when we add the dither */
float dithered = (*src * (126.0f)) + dither;
PaInt32 samp = 128 + (PaInt32) dithered;
PA_CLIP_( samp, 0x0000, 0x00FF );
*dest = (unsigned char) samp;
src += sourceStride;
dest += destinationStride;
......
......@@ -1009,6 +1009,10 @@ static OSStatus UpdateSampleRateFromDeviceProperty( PaMacCoreStream *stream, Aud
static OSStatus AudioDevicePropertyActualSampleRateListenerProc( AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void *inClientData )
{
PaMacCoreStream *stream = (PaMacCoreStream*)inClientData;
// Make sure the callback is operating on a stream that is still valid!
assert( stream->streamRepresentation.magic == PA_STREAM_MAGIC );
OSStatus osErr = UpdateSampleRateFromDeviceProperty( stream, inDevice, isInput );
if( osErr == noErr )
{
......@@ -1034,6 +1038,10 @@ static OSStatus AudioDevicePropertyGenericListenerProc( AudioDeviceID inDevice,
{
OSStatus osErr = noErr;
PaMacCoreStream *stream = (PaMacCoreStream*)inClientData;
// Make sure the callback is operating on a stream that is still valid!
assert( stream->streamRepresentation.magic == PA_STREAM_MAGIC );
PaMacCoreDeviceProperties *deviceProperties = isInput ? &stream->inputProperties : &stream->outputProperties;
UInt32 *valuePtr = NULL;
switch( inPropertyID )
......@@ -2107,7 +2115,7 @@ static OSStatus AudioIOProc( void *inRefCon,
PaMacCoreStream *stream = (PaMacCoreStream*)inRefCon;
const bool isRender = inBusNumber == OUTPUT_ELEMENT;
int callbackResult = paContinue ;
double hostTimeStampInPaTime = HOST_TIME_TO_PA_TIME(inTimeStamp->mHostTime);
double hostTimeStampInPaTime = HOST_TIME_TO_PA_TIME(inTimeStamp->mHostTime);
VVDBUG(("AudioIOProc()\n"));
......
......@@ -52,8 +52,12 @@
#if TEST_UNSIGNED
#define TEST_FORMAT paUInt8
typedef unsigned char sample_t;
#define SILENCE ((sample_t)0x80)
#else
#define TEST_FORMAT paInt8
typedef char sample_t;
#define SILENCE ((sample_t)0x00)
#endif
#ifndef M_PI
......@@ -62,11 +66,7 @@
typedef struct
{
#if TEST_UNSIGNED
unsigned char sine[TABLE_SIZE];
#else
char sine[TABLE_SIZE];
#endif
sample_t sine[TABLE_SIZE];
int left_phase;
int right_phase;
unsigned int framesToGo;
......@@ -84,7 +84,7 @@ static int patestCallback( const void *inputBuffer, void *outputBuffer,
void *userData )
{
paTestData *data = (paTestData*)userData;
char *out = (char*)outputBuffer;
sample_t *out = (sample_t*)outputBuffer;
int i;
int framesToCalc;
int finished = 0;
......@@ -114,14 +114,8 @@ static int patestCallback( const void *inputBuffer, void *outputBuffer,
/* zero remainder of final buffer */
for( ; i<(int)framesPerBuffer; i++ )
{
#if TEST_UNSIGNED
*out++ = (unsigned char) 0x80; /* left */
*out++ = (unsigned char) 0x80; /* right */
#else
*out++ = 0; /* left */
*out++ = 0; /* right */
#endif
*out++ = SILENCE; /* left */
*out++ = SILENCE; /* right */
}
return finished;
}
......@@ -145,10 +139,7 @@ int main(void)
/* initialise sinusoidal wavetable */
for( i=0; i<TABLE_SIZE; i++ )
{
data.sine[i] = (char) (127.0 * sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ));
#if TEST_UNSIGNED
data.sine[i] += (unsigned char) 0x80;
#endif
data.sine[i] = SILENCE + (char) (127.0 * sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ));
}
data.left_phase = data.right_phase = 0;
data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment