]> Repos - portaudio/commitdiff
added patest_suggested_vs_streaminfo_latency test and python graphing script
authorrossb <rossb@0f58301d-fd10-0410-b4af-bbb618454e57>
Thu, 4 Aug 2011 13:15:59 +0000 (13:15 +0000)
committerrossb <rossb@0f58301d-fd10-0410-b4af-bbb618454e57>
Thu, 4 Aug 2011 13:15:59 +0000 (13:15 +0000)
test/patest_suggested_vs_streaminfo_latency.c [new file with mode: 0644]
test/patest_suggested_vs_streaminfo_latency.py [new file with mode: 0644]

diff --git a/test/patest_suggested_vs_streaminfo_latency.c b/test/patest_suggested_vs_streaminfo_latency.c
new file mode 100644 (file)
index 0000000..41c5c7c
--- /dev/null
@@ -0,0 +1,216 @@
+/** @file patest_suggested_vs_streaminfo_latency.c\r
+       @ingroup test_src\r
+       @brief Print suggested vs. PaStreamInfo reported actual latency\r
+       @author Ross Bencina <rossb@audiomulch.com>\r
+*/\r
+/*\r
+ * $Id: patest_sine.c 1368 2008-03-01 00:38:27Z rossb $\r
+ *\r
+ * This program uses the PortAudio Portable Audio Library.\r
+ * For more information see: http://www.portaudio.com/\r
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ */\r
+\r
+/*\r
+ * The text above constitutes the entire PortAudio license; however, \r
+ * the PortAudio community also makes the following non-binding requests:\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version. It is also \r
+ * requested that these non-binding requests be included along with the \r
+ * license above.\r
+ */\r
+#include <stdio.h>\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
+\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
+\r
+\r
+// dummy callback. does nothing\r
+static int patestCallback( const void *inputBuffer, void *outputBuffer,\r
+                            unsigned long framesPerBuffer,\r
+                            const PaStreamCallbackTimeInfo* timeInfo,\r
+                            PaStreamCallbackFlags statusFlags,\r
+                            void *userData )\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
+int main(void);\r
+int main(void)\r
+{\r
+    PaStreamParameters outputParameters, inputParameters;\r
+    PaStream *stream;\r
+    PaError err;\r
+    int i;\r
+    PaTime suggestedLatency;\r
+    PaStreamInfo *streamInfo;\r
+    PaDeviceInfo *deviceInfo;\r
+\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
+\r
+    outputParameters.device = Pa_GetDefaultOutputDevice();\r
+    if (outputParameters.device == paNoDevice) {\r
+      fprintf(stderr,"Error: No default output device.\n");\r
+      goto error;\r
+    }\r
+    \r
+    outputParameters.channelCount = NUM_CHANNELS;\r
+    outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */\r
+    outputParameters.hostApiSpecificStreamInfo = NULL;\r
+\r
+    deviceInfo = Pa_GetDeviceInfo(outputParameters.device);\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
+    }\r
+    \r
+    inputParameters.channelCount = NUM_CHANNELS;\r
+    inputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */\r
+    inputParameters.hostApiSpecificStreamInfo = NULL;\r
+\r
+    deviceInfo = Pa_GetDeviceInfo(inputParameters.device);\r
+    printf( "# using input device id %d (%s, %s)\n", inputParameters.device, deviceInfo->name, Pa_GetHostApiInfo(deviceInfo->hostApi)->name );\r
+\r
+\r
+    printf( "# suggested latency, half duplex PaStreamInfo::outputLatency, half duplex PaStreamInfo::inputLatency, half duplex PaStreamInfo::outputLatency, half duplex PaStreamInfo::inputLatency\n" );\r
+    suggestedLatency = SUGGESTED_LATENCY_START_SECONDS;\r
+    while( suggestedLatency <= SUGGESTED_LATENCY_END_SECONDS ){\r
+\r
+        outputParameters.suggestedLatency = suggestedLatency;\r
+        inputParameters.suggestedLatency = suggestedLatency;\r
+\r
+        printf( "%f, ", suggestedLatency );\r
+\r
+        /* ------------------------------ output ------------------------------ */\r
+\r
+        err = Pa_OpenStream(\r
+                  &stream,\r
+                  NULL, /* no input */\r
+                  &outputParameters,\r
+                  SAMPLE_RATE,\r
+                  FRAMES_PER_BUFFER,\r
+                  paClipOff,      /* we won't output out of range samples so don't bother clipping them */\r
+                  patestCallback,\r
+                  0 );\r
+        if( err != paNoError ) goto error;\r
+\r
+        streamInfo = Pa_GetStreamInfo( stream );\r
+\r
+        printf( "%f,", streamInfo->outputLatency  );\r
+\r
+        err = Pa_CloseStream( stream );\r
+        if( err != paNoError ) goto error;\r
+\r
+        /* ------------------------------ input ------------------------------ */\r
+\r
+        err = Pa_OpenStream(\r
+                  &stream,\r
+                  &inputParameters, \r
+                  NULL, /* no output */\r
+                  SAMPLE_RATE,\r
+                  FRAMES_PER_BUFFER,\r
+                  paClipOff,      /* we won't output out of range samples so don't bother clipping them */\r
+                  patestCallback,\r
+                  0 );\r
+        if( err != paNoError ) goto error;\r
+\r
+        streamInfo = Pa_GetStreamInfo( stream );\r
+\r
+        printf( "%f,", streamInfo->inputLatency  );\r
+\r
+        err = Pa_CloseStream( stream );\r
+        if( err != paNoError ) goto error;\r
+\r
+        /* ------------------------------ full duplex ------------------------------ */\r
+\r
+        err = Pa_OpenStream(\r
+                  &stream,\r
+                  &inputParameters, \r
+                  &outputParameters,\r
+                  SAMPLE_RATE,\r
+                  FRAMES_PER_BUFFER,\r
+                  paClipOff,      /* we won't output out of range samples so don't bother clipping them */\r
+                  patestCallback,\r
+                  0 );\r
+        if( err != paNoError ) goto error;\r
+\r
+        streamInfo = Pa_GetStreamInfo( stream );\r
+\r
+        printf( "%f,%f", streamInfo->outputLatency, streamInfo->inputLatency );\r
+\r
+        err = Pa_CloseStream( stream );\r
+        if( err != paNoError ) goto error;\r
+\r
+        /* ------------------------------------------------------------ */\r
+\r
+        printf( "\n" );\r
+        suggestedLatency += SUGGESTED_LATENCY_INCREMENT_SECONDS;\r
+    }\r
+\r
+    Pa_Terminate();\r
+    printf("# Test finished.\n");\r
+    \r
+    return err;\r
+error:\r
+    Pa_Terminate();\r
+    fprintf( stderr, "An error occured while using the portaudio stream\n" );\r
+    fprintf( stderr, "Error number: %d\n", err );\r
+    fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );\r
+    return err;\r
+}\r
diff --git a/test/patest_suggested_vs_streaminfo_latency.py b/test/patest_suggested_vs_streaminfo_latency.py
new file mode 100644 (file)
index 0000000..a7a8d55
--- /dev/null
@@ -0,0 +1,58 @@
+#!/usr/bin/env python\r
+"""\r
+\r
+Run and graph the results of patest_suggested_vs_streaminfo_latency.c\r
+\r
+Requires matplotlib for plotting: http://matplotlib.sourceforge.net/\r
+\r
+"""\r
+import os\r
+from pylab import *\r
+import numpy\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
+\r
+\r
+def loadCsvData( dataFileName ):\r
+    params= ""\r
+    inputDevice = ""\r
+    outputDevice = ""\r
+\r
+    startLines = file(dataFileName).readlines(1024)\r
+    for line in startLines:\r
+        if "output device" in line:\r
+            outputDevice = line.strip(" \t\n\r#")\r
+        if "input device" in line:\r
+            inputDevice = line.strip(" \t\n\r#")\r
+    params = startLines[0].strip(" \t\n\r#")\r
+\r
+    data = numpy.loadtxt(dataFileName, delimiter=",", skiprows=4).transpose()\r
+\r
+    class R(object): pass\r
+    result = R()\r
+    result.titleInfo = '%s\n%s\n%s'%(params,inputDevice,outputDevice)\r
+    result.suggestedLatency = data[0]\r
+    result.halfDuplexOutputLatency = data[1]\r
+    result.halfDuplexInputLatency = data[2]\r
+    result.fullDuplexOutputLatency = data[3]\r
+    result.fullDuplexInputLatency = data[4]\r
+    return result;\r
+\r
+\r
+os.system(testExeName + ' > ' + dataFileName)\r
+\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
+\r
+title('PortAudio suggested (requested) vs. resulting (reported) stream latency\n%s'%d.titleInfo)\r
+ylabel('PaStreamInfo::{input,output}Latency (s)')\r
+xlabel('Pa_OpenStream suggestedLatency (s)')\r
+grid(True)\r
+\r
+show()\r