]> Repos - portaudio/commitdiff
Updated patest_suggested_vs_streaminfo_latency test. Python script now creates plots...
authorrossb <rossb@0f58301d-fd10-0410-b4af-bbb618454e57>
Thu, 11 Aug 2011 12:18:02 +0000 (12:18 +0000)
committerrossb <rossb@0f58301d-fd10-0410-b4af-bbb618454e57>
Thu, 11 Aug 2011 12:18:02 +0000 (12:18 +0000)
test/patest_suggested_vs_streaminfo_latency.c
test/patest_suggested_vs_streaminfo_latency.py

index 473f9a18a0a13786df73ba7c737766301a69a5b7..a6584a5bbbcd9d66341cedef96b0a426de4b02c4 100644 (file)
@@ -2,6 +2,12 @@
        @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
@@ -64,27 +68,6 @@ static int patestCallback( const void *inputBuffer, void *outputBuffer,
 {\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
@@ -93,7 +76,7 @@ static void usage()
     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
@@ -121,6 +104,7 @@ int main( int argc, const char* argv[] )
     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
@@ -129,10 +113,14 @@ int main( int argc, const char* argv[] )
         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
@@ -208,7 +196,7 @@ int main( int argc, const char* argv[] )
                   &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
@@ -228,7 +216,7 @@ int main( int argc, const char* argv[] )
                   &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
@@ -248,7 +236,7 @@ int main( int argc, const char* argv[] )
                   &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
index 9995949d6e4dae488aec10f047faefc1b62483cb..ad9591ae0aeb2f1bf1621f9c1fc2cb4baadc8444 100644 (file)
@@ -10,13 +10,16 @@ import os
 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
@@ -50,45 +53,93 @@ def loadCsvData( dataFileName ):
     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