@ingroup test_src\r
@brief Print suggested vs. PaStreamInfo reported actual latency\r
@author Ross Bencina <rossb@audiomulch.com>\r
+\r
+ Opens streams with a sequence of suggested latency values \r
+ from 0 to 2 seconds in .5ms intervals and gathers the resulting actual \r
+ latency values. Output a csv file and graph suggested vs. actual. Run \r
+ with framesPerBuffer unspecified, powers of 2 and multiples of 50 and \r
+ prime number buffer sizes.\r
*/\r
/*\r
* $Id: patest_sine.c 1368 2008-03-01 00:38:27Z rossb $\r
#include <math.h>\r
#include "portaudio.h"\r
\r
-#define NUM_SECONDS (5)\r
-#define SAMPLE_RATE (44100)\r
-#define FRAMES_PER_BUFFER (64)\r
-\r
-#define NUM_CHANNELS (2)\r
+#define SAMPLE_RATE (44100)\r
+#define FRAMES_PER_BUFFER (128)\r
+#define NUM_CHANNELS (2)\r
\r
#define SUGGESTED_LATENCY_START_SECONDS (0.0)\r
-#define SUGGESTED_LATENCY_END_SECONDS (.5)\r
-#define SUGGESTED_LATENCY_INCREMENT_SECONDS (0.0005) // half a millisecond increments\r
+#define SUGGESTED_LATENCY_END_SECONDS (2.0)\r
+#define SUGGESTED_LATENCY_INCREMENT_SECONDS (0.0005) /* half a millisecond increments */\r
\r
\r
-// dummy callback. does nothing\r
+/* dummy callback. does nothing. never gets called */\r
static int patestCallback( const void *inputBuffer, void *outputBuffer,\r
unsigned long framesPerBuffer,\r
const PaStreamCallbackTimeInfo* timeInfo,\r
{\r
}\r
\r
-\r
-/*\r
- TODO:\r
- \r
-\r
- A test that opens streams with a sequence of suggested latency values \r
- from 0 to 2 seconds in .5ms intervals and gathers the resulting actual \r
- latency values. Output a csv file and graph suggested vs. actual. Run \r
- with framesPerBuffer unspecified, powers of 2 and multiples of 50 and \r
- prime number buffer sizes.\r
-\r
- o- add command line parameters to specify frames per buffer, sample rate, devices\r
-\r
- o- test at standard sample rates\r
-\r
-\r
-\r
-\r
-\r
-*/\r
-\r
/*******************************************************************/\r
static void usage()\r
{\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, "Usage: x.exe input-device-index output-device-index sample-rate 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
PaStreamInfo *streamInfo;\r
PaDeviceInfo *deviceInfo;\r
int deviceCount;\r
+ float sampleRate = SAMPLE_RATE;\r
int framesPerBuffer = FRAMES_PER_BUFFER;\r
err = Pa_Initialize();\r
if( err != paNoError ) goto error;\r
usage();\r
\r
if( argc > 3 ){\r
- framesPerBuffer = atoi(argv[3]);\r
+ sampleRate = atoi(argv[3]);\r
+ }\r
+\r
+ if( argc > 4 ){\r
+ framesPerBuffer = atoi(argv[4]);\r
}\r
\r
- printf("# sample rate=%f, frames per buffer=%d\n", (float)SAMPLE_RATE, framesPerBuffer );\r
+ printf("# sample rate=%f, frames per buffer=%d\n", (float)sampleRate, framesPerBuffer );\r
\r
outputParameters.device = -1;\r
if( argc > 1 )\r
&stream,\r
NULL, /* no input */\r
&outputParameters,\r
- SAMPLE_RATE,\r
+ sampleRate,\r
framesPerBuffer,\r
paClipOff, /* we won't output out of range samples so don't bother clipping them */\r
patestCallback,\r
&stream,\r
&inputParameters, \r
NULL, /* no output */\r
- SAMPLE_RATE,\r
+ sampleRate,\r
framesPerBuffer,\r
paClipOff, /* we won't output out of range samples so don't bother clipping them */\r
patestCallback,\r
&stream,\r
&inputParameters, \r
&outputParameters,\r
- SAMPLE_RATE,\r
+ sampleRate,\r
framesPerBuffer,\r
paClipOff, /* we won't output out of range samples so don't bother clipping them */\r
patestCallback,\r
from pylab import *\r
import numpy\r
from matplotlib.backends.backend_pdf import PdfPages\r
-pdfFile = PdfPages('patest_suggested_vs_streaminfo_latency.pdf')\r
\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
+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
+outputDeviceIndex = -1 # -1 means default\r
+sampleRate = 44100\r
+pdfFilenameSuffix = "_wmme"\r
+\r
+pdfFile = PdfPages("patest_suggested_vs_streaminfo_latency_" + str(sampleRate) + pdfFilenameSuffix +".pdf") #output this pdf file\r
\r
\r
def loadCsvData( dataFileName ):\r
result.fullDuplexInputLatency = data[4]\r
return result;\r
\r
+\r
+def setFigureTitleAndAxisLabels( framesPerBufferString ):\r
+ title("PortAudio suggested (requested) vs. resulting (reported) stream latency\n" + framesPerBufferString)\r
+ ylabel("PaStreamInfo::{input,output}Latency (s)")\r
+ xlabel("Pa_OpenStream suggestedLatency (s)")\r
+ grid(True)\r
+ legend(loc="upper left")\r
+\r
+def setDisplayRangeSeconds( maxSeconds ):\r
+ xlim(0, maxSeconds)\r
+ ylim(0, maxSeconds)\r
+\r
+\r
# run the test with different frames per buffer values:\r
\r
-framesPerBufferValues = [0]\r
+compositeTestFramesPerBufferValues = [0]\r
# powers of two\r
-#for i in range (1,11):\r
-# framesPerBufferValues.append( 2 ^ i )\r
+for i in range (1,11):\r
+ compositeTestFramesPerBufferValues.append( pow(2,i) )\r
\r
-# could also test: multiples of 10, random numbers, powers of primes, etc\r
+# multiples of 50\r
+for i in range (1,20):\r
+ compositeTestFramesPerBufferValues.append( i * 50 )\r
\r
-isFirst = True \r
+# 10ms buffer sizes\r
+compositeTestFramesPerBufferValues.append( 441 )\r
+compositeTestFramesPerBufferValues.append( 882 )\r
\r
-for framesPerBuffer in framesPerBufferValues:\r
+individualPlotFramesPerBufferValues = [0,64,128,256,512] #output separate plots for these\r
\r
- os.system(testExeName + " -1 -1 " + str(framesPerBuffer) + ' > ' + dataFileName)\r
+isFirst = True \r
+\r
+for framesPerBuffer in compositeTestFramesPerBufferValues:\r
+ commandString = testExeName + " " + str(inputDeviceIndex) + " " + str(outputDeviceIndex) + " " + str(sampleRate) + " " + str(framesPerBuffer) + ' > ' + dataFileName\r
+ print commandString\r
+ os.system(commandString)\r
\r
d = loadCsvData(dataFileName)\r
\r
if isFirst:\r
- figure(1)\r
+ figure(1) # title sheet\r
gcf().text(0.1, 0.0,\r
- 'patest_suggested_vs_streaminfo_latency\n%s\n%s\n%s\n'%(d.inputDevice,d.outputDevice,d.sampleRate))\r
+ "patest_suggested_vs_streaminfo_latency\n%s\n%s\n%s\n"%(d.inputDevice,d.outputDevice,d.sampleRate))\r
pdfFile.savefig()\r
- isFirst = False\r
- \r
- figure(2)\r
+ \r
+ \r
+ figure(2) # composite plot, includes all compositeTestFramesPerBufferValues\r
\r
- plot( d.suggestedLatency, d.suggestedLatency )\r
+ if isFirst:\r
+ plot( d.suggestedLatency, d.suggestedLatency, label="Suggested latency" )\r
+ \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'%str(framesPerBufferValues))\r
-ylabel('PaStreamInfo::{input,output}Latency (s)')\r
-xlabel('Pa_OpenStream suggestedLatency (s)')\r
-grid(True)\r
+ if framesPerBuffer in individualPlotFramesPerBufferValues: # individual plots\r
+ figure( 3 + individualPlotFramesPerBufferValues.index(framesPerBuffer) )\r
+\r
+ plot( d.suggestedLatency, d.suggestedLatency, label="Suggested latency" )\r
+ plot( d.suggestedLatency, d.halfDuplexOutputLatency, label="Half-duplex output latency" )\r
+ plot( d.suggestedLatency, d.halfDuplexInputLatency, label="Half-duplex input latency" )\r
+ plot( d.suggestedLatency, d.fullDuplexOutputLatency, label="Full-duplex output latency" )\r
+ plot( d.suggestedLatency, d.fullDuplexInputLatency, label="Full-duplex input latency" )\r
+\r
+ if framesPerBuffer == 0:\r
+ framesPerBufferText = "paFramesPerBufferUnspecified"\r
+ else:\r
+ framesPerBufferText = str(framesPerBuffer)\r
+ setFigureTitleAndAxisLabels( "user frames per buffer: "+str(framesPerBufferText) )\r
+ setDisplayRangeSeconds(2.2)\r
+ pdfFile.savefig()\r
+ setDisplayRangeSeconds(0.1)\r
+ setFigureTitleAndAxisLabels( "user frames per buffer: "+str(framesPerBufferText)+" (detail)" )\r
+ pdfFile.savefig()\r
+\r
+ isFirst = False\r
\r
+figure(2)\r
+setFigureTitleAndAxisLabels( "composite of frames per buffer values:\n"+str(compositeTestFramesPerBufferValues) )\r
+setDisplayRangeSeconds(2.2)\r
+pdfFile.savefig()\r
+setDisplayRangeSeconds(0.1)\r
+setFigureTitleAndAxisLabels( "composite of frames per buffer values:\n"+str(compositeTestFramesPerBufferValues)+" (detail)" )\r
pdfFile.savefig()\r
\r
pdfFile.close()\r
\r
-show()\r
+#uncomment this to display interactively, otherwise we just output a pdf\r
+#show()\r