\r
\r
\r
+\r
+\r
*/\r
\r
/*******************************************************************/\r
-int main(void);\r
-int main(void)\r
+static void usage()\r
+{\r
+ int i;\r
+ const PaDeviceInfo *deviceInfo;\r
+ const char *channelString;\r
+\r
+ fprintf( stderr, "PortAudio suggested (requested) vs. resulting (reported) stream latency test\n" );\r
+ fprintf( stderr, "Usage: x.exe input-device-index output-device-index frames-per-buffer\n" );\r
+ fprintf( stderr, "Use -1 for default device index, or use one of these:\n" );\r
+ for( i=0; i < Pa_GetDeviceCount(); ++i ){\r
+ deviceInfo = Pa_GetDeviceInfo(i);\r
+ if( deviceInfo->maxInputChannels > 0 && deviceInfo->maxOutputChannels > 0 )\r
+ channelString = "full-duplex";\r
+ else if( deviceInfo->maxInputChannels > 0 )\r
+ channelString = "input only";\r
+ else\r
+ channelString = "output only";\r
+\r
+ fprintf( stderr, "%d (%s, %s, %s)\n", i, deviceInfo->name, Pa_GetHostApiInfo(deviceInfo->hostApi)->name, channelString );\r
+ }\r
+ Pa_Terminate();\r
+ exit(-1);\r
+}\r
+\r
+int main( int argc, const char* argv[] );\r
+int main( int argc, const char* argv[] )\r
{\r
PaStreamParameters outputParameters, inputParameters;\r
PaStream *stream;\r
PaTime suggestedLatency;\r
PaStreamInfo *streamInfo;\r
PaDeviceInfo *deviceInfo;\r
-\r
+ int deviceCount;\r
+ int framesPerBuffer = FRAMES_PER_BUFFER;\r
err = Pa_Initialize();\r
if( err != paNoError ) goto error;\r
\r
- printf("# sample rate=%f, frames per buffer=%d\n", (float)SAMPLE_RATE, FRAMES_PER_BUFFER );\r
+ if( argc > 1 && strcmp(argv[1],"-h") == 0 )\r
+ usage();\r
\r
- outputParameters.device = Pa_GetDefaultOutputDevice();\r
- if (outputParameters.device == paNoDevice) {\r
- fprintf(stderr,"Error: No default output device.\n");\r
- goto error;\r
+ if( argc > 3 ){\r
+ framesPerBuffer = atoi(argv[3]);\r
+ }\r
+\r
+ printf("# sample rate=%f, frames per buffer=%d\n", (float)SAMPLE_RATE, framesPerBuffer );\r
+\r
+ outputParameters.device = -1;\r
+ if( argc > 1 )\r
+ outputParameters.device = atoi(argv[1]);\r
+ if( outputParameters.device == -1 ){\r
+ outputParameters.device = Pa_GetDefaultOutputDevice();\r
+ if (outputParameters.device == paNoDevice) {\r
+ fprintf(stderr,"Error: No default output device available.\n");\r
+ goto error;\r
+ }\r
+ }else{\r
+ deviceInfo = Pa_GetDeviceInfo(outputParameters.device);\r
+ if( !deviceInfo ){\r
+ fprintf(stderr,"Error: Invalid output device index.\n");\r
+ usage();\r
+ }\r
+ if( deviceInfo->maxOutputChannels == 0 ){\r
+ fprintf(stderr,"Error: Specified output device has no output channels (an input only device?).\n");\r
+ usage();\r
+ }\r
}\r
\r
outputParameters.channelCount = NUM_CHANNELS;\r
printf( "# using output device id %d (%s, %s)\n", outputParameters.device, deviceInfo->name, Pa_GetHostApiInfo(deviceInfo->hostApi)->name );\r
\r
\r
- inputParameters.device = Pa_GetDefaultInputDevice();\r
- if (inputParameters.device == paNoDevice) {\r
- fprintf(stderr,"Error: No default input device.\n");\r
- goto error;\r
+ inputParameters.device = -1;\r
+ if( argc > 2 )\r
+ inputParameters.device = atoi(argv[1]);\r
+ if( inputParameters.device == -1 ){\r
+ inputParameters.device = Pa_GetDefaultInputDevice();\r
+ if (inputParameters.device == paNoDevice) {\r
+ fprintf(stderr,"Error: No default input device available.\n");\r
+ goto error;\r
+ }\r
+ }else{\r
+ deviceInfo = Pa_GetDeviceInfo(inputParameters.device);\r
+ if( !deviceInfo ){\r
+ fprintf(stderr,"Error: Invalid input device index.\n");\r
+ usage();\r
+ }\r
+ if( deviceInfo->maxInputChannels == 0 ){\r
+ fprintf(stderr,"Error: Specified input device has no input channels (an output only device?).\n");\r
+ usage();\r
+ }\r
}\r
+\r
\r
inputParameters.channelCount = NUM_CHANNELS;\r
inputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */\r
NULL, /* no input */\r
&outputParameters,\r
SAMPLE_RATE,\r
- FRAMES_PER_BUFFER,\r
+ framesPerBuffer,\r
paClipOff, /* we won't output out of range samples so don't bother clipping them */\r
patestCallback,\r
0 );\r
&inputParameters, \r
NULL, /* no output */\r
SAMPLE_RATE,\r
- FRAMES_PER_BUFFER,\r
+ framesPerBuffer,\r
paClipOff, /* we won't output out of range samples so don't bother clipping them */\r
patestCallback,\r
0 );\r
&inputParameters, \r
&outputParameters,\r
SAMPLE_RATE,\r
- FRAMES_PER_BUFFER,\r
+ framesPerBuffer,\r
paClipOff, /* we won't output out of range samples so don't bother clipping them */\r
patestCallback,\r
0 );\r
testExeName = "PATest.exe" # rename to whatever the compiled patest_suggested_vs_streaminfo_latency.c binary is\r
dataFileName = 'patest_suggested_vs_streaminfo_latency.csv' # code below calls the exe to generate this file\r
\r
+inputDeviceIndex = -1 # -1 means default\r
+inputDeviceIndex = -1 # -1 means default\r
+\r
\r
def loadCsvData( dataFileName ):\r
params= ""\r
result.fullDuplexInputLatency = data[4]\r
return result;\r
\r
+# run the test with different frames per buffer values:\r
+\r
+framesPerBufferValues = [0]\r
+# powers of two\r
+#for i in range (1,11):\r
+# framesPerBufferValues.append( 2 ^ i )\r
+\r
+# could also test: multiples of 10, random numbers, powers of primes, etc\r
+\r
+ \r
+\r
+for framesPerBuffer in framesPerBufferValues:\r
\r
-os.system(testExeName + ' > ' + dataFileName)\r
+ os.system(testExeName + " -1 -1 " + str(framesPerBuffer) + ' > ' + dataFileName)\r
\r
-d = loadCsvData(dataFileName)\r
+ d = loadCsvData(dataFileName)\r
\r
-plot( d.suggestedLatency, d.suggestedLatency )\r
-plot( d.suggestedLatency, d.halfDuplexOutputLatency )\r
-plot( d.suggestedLatency, d.halfDuplexInputLatency )\r
-plot( d.suggestedLatency, d.fullDuplexOutputLatency )\r
-plot( d.suggestedLatency, d.fullDuplexInputLatency )\r
+ plot( d.suggestedLatency, d.suggestedLatency )\r
+ plot( d.suggestedLatency, d.halfDuplexOutputLatency )\r
+ plot( d.suggestedLatency, d.halfDuplexInputLatency )\r
+ plot( d.suggestedLatency, d.fullDuplexOutputLatency )\r
+ plot( d.suggestedLatency, d.fullDuplexInputLatency )\r
\r
title('PortAudio suggested (requested) vs. resulting (reported) stream latency\n%s'%d.titleInfo)\r
ylabel('PaStreamInfo::{input,output}Latency (s)')\r