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:
parent
1a5c410f7f
commit
5f869e787e
1 changed files with 137 additions and 55 deletions
192
qa/paqa_devs.c
192
qa/paqa_devs.c
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue