]> Repos - portaudio/commitdiff
paqa_devs: test default device
authorPhil Burk <philburk@mobileer.com>
Sat, 19 Dec 2020 23:59:23 +0000 (15:59 -0800)
committerPhil Burk <philburk@mobileer.com>
Sat, 26 Dec 2020 16:47:56 +0000 (08:47 -0800)
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.

qa/paqa_devs.c

index 721b07f14fc59ceb5b069f3260000facbfa6bfd4..fae9f25f681bcbd6b4eb3fd029d0de03ecf6571e 100644 (file)
@@ -1,13 +1,13 @@
 /** @file paqa_devs.c
-       @ingroup qa_src
+    @ingroup qa_src
     @brief Self Testing Quality Assurance app for PortAudio
-       Try to open each device and run through all the
-       possible configurations. This test does not verify
+    Try to open the default devices and run through all the
+    possible configurations. This test does not verify
     that the configuration works well. It just verifies
     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 
     Pa_IsFormatSupported(). Uses same 'standard' sample rates
  */
 
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <math.h>
 #include "portaudio.h"
 #include "pa_trace.h"
 
 /****************************************** Definitions ***********/
-#define MODE_INPUT      (0)
-#define MODE_OUTPUT     (1)
-#define MAX_TEST_CHANNELS  4
+#define MODE_INPUT         (0)
+#define MODE_OUTPUT        (1)
+#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
 {
@@ -67,13 +73,13 @@ typedef struct PaQaData
     int            numChannels;
     int            bytesPerSample;
     int            mode;
-    short          sawPhase;
+    float          phase;
     PaSampleFormat format;
 }
 PaQaData;
 
 /****************************************** Prototypes ***********/
-static void TestDevices( int mode );
+static void TestDevices( int mode, int allDevices );
 static void TestFormats( int mode, PaDeviceIndex deviceID, double sampleRate,
                          int numChannels );
 static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate,
@@ -107,6 +113,14 @@ static int gNumFailed = 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.
 ** 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,
                        void *userData )
 {
-    unsigned long  i;
-    short          phase;
+    unsigned long frameIndex;
+    unsigned long channelIndex;
+    float sample;
     PaQaData *data = (PaQaData *) userData;
     (void) inputBuffer;
 
-    /* Play simple sawtooth wave. */
+    /* Play simple sine wave. */
     if( data->mode == MODE_OUTPUT )
     {
-        phase = data->sawPhase;
         switch( data->format )
         {
         case paFloat32:
             {
                 float *out =  (float *) outputBuffer;
-                for( i=0; i<framesPerBuffer; i++ )
+                for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ )
                 {
-                    phase += 0x123;
-                    *out++ = (float) (phase * (1.0 / 32768.0));
-                    if( data->numChannels == 2 )
+                    sample = NextSineSample( data );
+                    for( channelIndex = 0; channelIndex < data->numChannels; channelIndex++ )
                     {
-                        *out++ = (float) (phase * (1.0 / 32768.0));
+                        *out++ = sample;
                     }
                 }
             }
@@ -147,13 +160,12 @@ static int QaCallback( const void *inputBuffer, void *outputBuffer,
         case paInt32:
             {
                 int *out =  (int *) outputBuffer;
-                for( i=0; i<framesPerBuffer; i++ )
+                for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ )
                 {
-                    phase += 0x123;
-                    *out++ = ((int) phase ) << 16;
-                    if( data->numChannels == 2 )
+                    sample = NextSineSample( data );
+                    for( channelIndex = 0; channelIndex < data->numChannels; channelIndex++ )
                     {
-                        *out++ = ((int) phase ) << 16;
+                        *out++ = ((int)(sample * 0x00800000)) << 8;
                     }
                 }
             }
@@ -162,13 +174,12 @@ static int QaCallback( const void *inputBuffer, void *outputBuffer,
         case paInt16:
             {
                 short *out =  (short *) outputBuffer;
-                for( i=0; i<framesPerBuffer; i++ )
+                for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ )
                 {
-                    phase += 0x123;
-                    *out++ = phase;
-                    if( data->numChannels == 2 )
+                    sample = NextSineSample( data );
+                    for( channelIndex = 0; channelIndex < data->numChannels; channelIndex++ )
                     {
-                        *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 long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample;
-                for( i=0; i<numBytes; i++ )
-                {
-                    *out++ = 0;
-                }
+                memset(out, 0, numBytes);
             }
             break;
         }
-        data->sawPhase = phase;
     }
     /* Are we through yet? */
     if( data->framesLeft > framesPerBuffer )
@@ -203,15 +210,78 @@ static int QaCallback( const void *inputBuffer, void *outputBuffer,
 }
 
 /*******************************************************************/
-int main(void);
-int main(void)
+static void usage( const char *name )
+{
+    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;
+    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) );
-    printf("Test OUTPUT ---------------\n");
-    TestDevices( MODE_OUTPUT );
-    printf("Test INPUT ---------------\n");
-    TestDevices( MODE_INPUT );
+
+    if( testOutput )
+    {
+        printf("\n---- Test OUTPUT ---------------\n");
+        TestDevices( MODE_OUTPUT, allDevices );
+    }
+    if( testInput )
+    {
+        printf("\n---- Test INPUT ---------------\n");
+        TestDevices( MODE_INPUT, allDevices );
+    }
+
 error:
     Pa_Terminate();
     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. */
-static void TestDevices( int mode )
+static void TestDevices( int mode, int allDevices )
 {
     int id, jc, i;
     int maxChannels;
+    int isDefault;
     const PaDeviceInfo *pdi;
     static double standardSampleRates[] = {  8000.0,  9600.0, 11025.0, 12000.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. */
     {
         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 )
             maxChannels = MAX_TEST_CHANNELS;
+
+        if (!allDevices && !isDefault) continue; // skip this device
         
         for( jc=1; jc<=maxChannels; jc++ )
         {
-            printf("\n========================================================================\n");
+            printf("\n===========================================================\n");
             printf("            Device = %s\n", pdi->name );
-            printf("========================================================================\n");
+            printf("===========================================================\n");
             /* Try each standard sample rate. */
             for( i=0; standardSampleRates[i] > 0; i++ )
             {
@@ -299,32 +378,35 @@ static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate,
         inputParameters.device       = deviceID;
         inputParameters.channelCount = numChannels;
         inputParameters.sampleFormat = format;
-        inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
+        inputParameters.suggestedLatency =
+                Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
         inputParameters.hostApiSpecificStreamInfo = NULL;
         ipp = &inputParameters;
     }
     else
     {
-          ipp = NULL;
-       }
-       
+       ipp = NULL;
+    }
+
     if( mode == MODE_OUTPUT )
     {
         outputParameters.device       = deviceID;
         outputParameters.channelCount = numChannels;
         outputParameters.sampleFormat = format;
-        outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
+        outputParameters.suggestedLatency =
+                Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
         outputParameters.hostApiSpecificStreamInfo = NULL;
         opp = &outputParameters;
     }
     else
     {
-               opp = NULL;
-       }
-       
+        opp = NULL;
+    }
+
     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",
                 deviceID, sampleRate, numChannels, (unsigned long)format);
         EXPECT( ((result = Pa_OpenStream( &stream,
@@ -353,7 +435,7 @@ static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate,
             oldStamp = Pa_GetStreamTime(stream);
             Pa_Sleep(msec);
             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) );
             /* Check to make sure callback is decrementing framesLeft. */
             oldFrames = myData.framesLeft;