paqa_devs: test default device

Use sine wave instead of sawtooth because it is
easier to hear glitches.

Add some options:
    -a - Test ALL devices, otherwise just the default devices.
    -i - Test INPUT only.
    -o - Test OUTPUT only.
This commit is contained in:
Phil Burk 2020-12-19 15:59:23 -08:00
commit 5f869e787e

View file

@ -1,13 +1,13 @@
/** @file paqa_devs.c /** @file paqa_devs.c
@ingroup qa_src @ingroup qa_src
@brief Self Testing Quality Assurance app for PortAudio @brief Self Testing Quality Assurance app for PortAudio
Try to open each device and run through all the Try to open the default devices and run through all the
possible configurations. This test does not verify possible configurations. This test does not verify
that the configuration works well. It just verifies that the configuration works well. It just verifies
that it does not crash. It requires a human to listen to that it does not crash. It requires a human to listen to
the outputs. the sine wave outputs.
@author Phil Burk http://www.softsynth.com @author Phil Burk http://www.softsynth.com
Pieter adapted to V19 API. Test now relies heavily on Pieter adapted to V19 API. Test now relies heavily on
Pa_IsFormatSupported(). Uses same 'standard' sample rates Pa_IsFormatSupported(). Uses same 'standard' sample rates
@ -52,14 +52,20 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h> #include <math.h>
#include "portaudio.h" #include "portaudio.h"
#include "pa_trace.h" #include "pa_trace.h"
/****************************************** Definitions ***********/ /****************************************** Definitions ***********/
#define MODE_INPUT (0) #define MODE_INPUT (0)
#define MODE_OUTPUT (1) #define MODE_OUTPUT (1)
#define MAX_TEST_CHANNELS 4 #define MAX_TEST_CHANNELS (4)
#define LOWEST_FREQUENCY (300.0)
#define LOWEST_SAMPLE_RATE (8000.0)
#define PHASE_INCREMENT (2.0 * M_PI * LOWEST_FREQUENCY / LOWEST_SAMPLE_RATE)
#define SINE_AMPLITUDE (0.2)
typedef struct PaQaData typedef struct PaQaData
{ {
@ -67,13 +73,13 @@ typedef struct PaQaData
int numChannels; int numChannels;
int bytesPerSample; int bytesPerSample;
int mode; int mode;
short sawPhase; float phase;
PaSampleFormat format; PaSampleFormat format;
} }
PaQaData; PaQaData;
/****************************************** Prototypes ***********/ /****************************************** Prototypes ***********/
static void TestDevices( int mode ); static void TestDevices( int mode, int allDevices );
static void TestFormats( int mode, PaDeviceIndex deviceID, double sampleRate, static void TestFormats( int mode, PaDeviceIndex deviceID, double sampleRate,
int numChannels ); int numChannels );
static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate, static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate,
@ -107,6 +113,14 @@ static int gNumFailed = 0;
} \ } \
} while(0) } while(0)
static float NextSineSample( PaQaData *data )
{
float phase = data->phase + PHASE_INCREMENT;
if( phase > M_PI ) phase -= 2.0 * M_PI;
data->phase = phase;
return sinf(phase) * SINE_AMPLITUDE;
}
/*******************************************************************/ /*******************************************************************/
/* This routine will be called by the PortAudio engine when audio is needed. /* This routine will be called by the PortAudio engine when audio is needed.
** It may be called at interrupt level on some machines so don't do anything ** It may be called at interrupt level on some machines so don't do anything
@ -118,27 +132,26 @@ static int QaCallback( const void *inputBuffer, void *outputBuffer,
PaStreamCallbackFlags statusFlags, PaStreamCallbackFlags statusFlags,
void *userData ) void *userData )
{ {
unsigned long i; unsigned long frameIndex;
short phase; unsigned long channelIndex;
float sample;
PaQaData *data = (PaQaData *) userData; PaQaData *data = (PaQaData *) userData;
(void) inputBuffer; (void) inputBuffer;
/* Play simple sawtooth wave. */ /* Play simple sine wave. */
if( data->mode == MODE_OUTPUT ) if( data->mode == MODE_OUTPUT )
{ {
phase = data->sawPhase;
switch( data->format ) switch( data->format )
{ {
case paFloat32: case paFloat32:
{ {
float *out = (float *) outputBuffer; float *out = (float *) outputBuffer;
for( i=0; i<framesPerBuffer; i++ ) for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ )
{ {
phase += 0x123; sample = NextSineSample( data );
*out++ = (float) (phase * (1.0 / 32768.0)); for( channelIndex = 0; channelIndex < data->numChannels; channelIndex++ )
if( data->numChannels == 2 )
{ {
*out++ = (float) (phase * (1.0 / 32768.0)); *out++ = sample;
} }
} }
} }
@ -147,13 +160,12 @@ static int QaCallback( const void *inputBuffer, void *outputBuffer,
case paInt32: case paInt32:
{ {
int *out = (int *) outputBuffer; int *out = (int *) outputBuffer;
for( i=0; i<framesPerBuffer; i++ ) for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ )
{ {
phase += 0x123; sample = NextSineSample( data );
*out++ = ((int) phase ) << 16; for( channelIndex = 0; channelIndex < data->numChannels; channelIndex++ )
if( data->numChannels == 2 )
{ {
*out++ = ((int) phase ) << 16; *out++ = ((int)(sample * 0x00800000)) << 8;
} }
} }
} }
@ -162,13 +174,12 @@ static int QaCallback( const void *inputBuffer, void *outputBuffer,
case paInt16: case paInt16:
{ {
short *out = (short *) outputBuffer; short *out = (short *) outputBuffer;
for( i=0; i<framesPerBuffer; i++ ) for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ )
{ {
phase += 0x123; sample = NextSineSample( data );
*out++ = phase; for( channelIndex = 0; channelIndex < data->numChannels; channelIndex++ )
if( data->numChannels == 2 )
{ {
*out++ = phase; *out++ = (short)(sample * 32767);
} }
} }
} }
@ -178,14 +189,10 @@ static int QaCallback( const void *inputBuffer, void *outputBuffer,
{ {
unsigned char *out = (unsigned char *) outputBuffer; unsigned char *out = (unsigned char *) outputBuffer;
unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample; unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample;
for( i=0; i<numBytes; i++ ) memset(out, 0, numBytes);
{
*out++ = 0;
}
} }
break; break;
} }
data->sawPhase = phase;
} }
/* Are we through yet? */ /* Are we through yet? */
if( data->framesLeft > framesPerBuffer ) if( data->framesLeft > framesPerBuffer )
@ -203,15 +210,78 @@ static int QaCallback( const void *inputBuffer, void *outputBuffer,
} }
/*******************************************************************/ /*******************************************************************/
int main(void); static void usage( const char *name )
int main(void)
{ {
printf("%s [-a]\n", name);
printf(" -a - Test ALL devices, otherwise just the default devices.\n");
printf(" -i - Test INPUT only.\n");
printf(" -o - Test OUTPUT only.\n");
printf(" -? - Help\n");
}
/*******************************************************************/
int main( int argc, char **argv );
int main( int argc, char **argv )
{
int i;
PaError result; PaError result;
int allDevices = 0;
int testOutput = 1;
int testInput = 1;
char *executableName = argv[0];
/* Parse command line parameters. */
i = 1;
while( i<argc )
{
char *arg = argv[i];
if( arg[0] == '-' )
{
switch(arg[1])
{
case 'a':
allDevices = 1;
break;
case 'i':
testOutput = 0;
break;
case 'o':
testInput = 0;
break;
default:
printf("Illegal option: %s\n", arg);
case '?':
usage( executableName );
exit(1);
break;
}
}
else
{
printf("Illegal argument: %s\n", arg);
usage( executableName );
return 1;
}
i += 1;
}
EXPECT(sizeof(short) == 2); /* The callback assumes we have 16-bit shorts. */
EXPECT(sizeof(int) == 4); /* The callback assumes we have 32-bit ints. */
EXPECT( ((result=Pa_Initialize()) == 0) ); EXPECT( ((result=Pa_Initialize()) == 0) );
printf("Test OUTPUT ---------------\n");
TestDevices( MODE_OUTPUT ); if( testOutput )
printf("Test INPUT ---------------\n"); {
TestDevices( MODE_INPUT ); printf("\n---- Test OUTPUT ---------------\n");
TestDevices( MODE_OUTPUT, allDevices );
}
if( testInput )
{
printf("\n---- Test INPUT ---------------\n");
TestDevices( MODE_INPUT, allDevices );
}
error: error:
Pa_Terminate(); Pa_Terminate();
printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed ); printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed );
@ -220,10 +290,11 @@ error:
/******************************************************************* /*******************************************************************
* Try each output device, through its full range of capabilities. */ * Try each output device, through its full range of capabilities. */
static void TestDevices( int mode ) static void TestDevices( int mode, int allDevices )
{ {
int id, jc, i; int id, jc, i;
int maxChannels; int maxChannels;
int isDefault;
const PaDeviceInfo *pdi; const PaDeviceInfo *pdi;
static double standardSampleRates[] = { 8000.0, 9600.0, 11025.0, 12000.0, static double standardSampleRates[] = { 8000.0, 9600.0, 11025.0, 12000.0,
16000.0, 22050.0, 24000.0, 16000.0, 22050.0, 24000.0,
@ -234,16 +305,24 @@ static void TestDevices( int mode )
for( id=0; id<numDevices; id++ ) /* Iterate through all devices. */ for( id=0; id<numDevices; id++ ) /* Iterate through all devices. */
{ {
pdi = Pa_GetDeviceInfo( id ); pdi = Pa_GetDeviceInfo( id );
/* Try 1 to maxChannels on each device. */
maxChannels = (( mode == MODE_INPUT ) ? pdi->maxInputChannels : pdi->maxOutputChannels); if( mode == MODE_INPUT ) {
maxChannels = pdi->maxInputChannels;
isDefault = ( id == Pa_GetDefaultInputDevice());
} else {
maxChannels = pdi->maxOutputChannels;
isDefault = ( id == Pa_GetDefaultOutputDevice());
}
if( maxChannels > MAX_TEST_CHANNELS ) if( maxChannels > MAX_TEST_CHANNELS )
maxChannels = MAX_TEST_CHANNELS; maxChannels = MAX_TEST_CHANNELS;
if (!allDevices && !isDefault) continue; // skip this device
for( jc=1; jc<=maxChannels; jc++ ) for( jc=1; jc<=maxChannels; jc++ )
{ {
printf("\n========================================================================\n"); printf("\n===========================================================\n");
printf(" Device = %s\n", pdi->name ); printf(" Device = %s\n", pdi->name );
printf("========================================================================\n"); printf("===========================================================\n");
/* Try each standard sample rate. */ /* Try each standard sample rate. */
for( i=0; standardSampleRates[i] > 0; i++ ) for( i=0; standardSampleRates[i] > 0; i++ )
{ {
@ -299,32 +378,35 @@ static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate,
inputParameters.device = deviceID; inputParameters.device = deviceID;
inputParameters.channelCount = numChannels; inputParameters.channelCount = numChannels;
inputParameters.sampleFormat = format; inputParameters.sampleFormat = format;
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency; inputParameters.suggestedLatency =
Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = NULL; inputParameters.hostApiSpecificStreamInfo = NULL;
ipp = &inputParameters; ipp = &inputParameters;
} }
else else
{ {
ipp = NULL; ipp = NULL;
} }
if( mode == MODE_OUTPUT ) if( mode == MODE_OUTPUT )
{ {
outputParameters.device = deviceID; outputParameters.device = deviceID;
outputParameters.channelCount = numChannels; outputParameters.channelCount = numChannels;
outputParameters.sampleFormat = format; outputParameters.sampleFormat = format;
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; outputParameters.suggestedLatency =
Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
outputParameters.hostApiSpecificStreamInfo = NULL; outputParameters.hostApiSpecificStreamInfo = NULL;
opp = &outputParameters; opp = &outputParameters;
} }
else else
{ {
opp = NULL; opp = NULL;
} }
if(paFormatIsSupported == Pa_IsFormatSupported( ipp, opp, sampleRate )) if(paFormatIsSupported == Pa_IsFormatSupported( ipp, opp, sampleRate ))
{ {
printf("------ TestAdvance: %s, device = %d, rate = %g, numChannels = %d, format = %lu -------\n", printf("------ TestAdvance: %s, device = %d, rate = %g"
", numChannels = %d, format = %lu -------\n",
( mode == MODE_INPUT ) ? "INPUT" : "OUTPUT", ( mode == MODE_INPUT ) ? "INPUT" : "OUTPUT",
deviceID, sampleRate, numChannels, (unsigned long)format); deviceID, sampleRate, numChannels, (unsigned long)format);
EXPECT( ((result = Pa_OpenStream( &stream, EXPECT( ((result = Pa_OpenStream( &stream,
@ -353,7 +435,7 @@ static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate,
oldStamp = Pa_GetStreamTime(stream); oldStamp = Pa_GetStreamTime(stream);
Pa_Sleep(msec); Pa_Sleep(msec);
newStamp = Pa_GetStreamTime(stream); newStamp = Pa_GetStreamTime(stream);
printf("oldStamp = %9.6f, newStamp = %9.6f\n", oldStamp, newStamp ); /**/ printf("oldStamp = %9.6f, newStamp = %9.6f\n", oldStamp, newStamp ); /**/
EXPECT( (oldStamp < newStamp) ); EXPECT( (oldStamp < newStamp) );
/* Check to make sure callback is decrementing framesLeft. */ /* Check to make sure callback is decrementing framesLeft. */
oldFrames = myData.framesLeft; oldFrames = myData.framesLeft;