cannam@140
|
1 #!/usr/bin/env python
|
cannam@140
|
2 """
|
cannam@140
|
3
|
cannam@140
|
4 Run and graph the results of patest_suggested_vs_streaminfo_latency.c
|
cannam@140
|
5
|
cannam@140
|
6 Requires matplotlib for plotting: http://matplotlib.sourceforge.net/
|
cannam@140
|
7
|
cannam@140
|
8 """
|
cannam@140
|
9 import os
|
cannam@140
|
10 from pylab import *
|
cannam@140
|
11 import numpy
|
cannam@140
|
12 from matplotlib.backends.backend_pdf import PdfPages
|
cannam@140
|
13
|
cannam@140
|
14 testExeName = "PATest.exe" # rename to whatever the compiled patest_suggested_vs_streaminfo_latency.c binary is
|
cannam@140
|
15 dataFileName = "patest_suggested_vs_streaminfo_latency.csv" # code below calls the exe to generate this file
|
cannam@140
|
16
|
cannam@140
|
17 inputDeviceIndex = -1 # -1 means default
|
cannam@140
|
18 outputDeviceIndex = -1 # -1 means default
|
cannam@140
|
19 sampleRate = 44100
|
cannam@140
|
20 pdfFilenameSuffix = "_wmme"
|
cannam@140
|
21
|
cannam@140
|
22 pdfFile = PdfPages("patest_suggested_vs_streaminfo_latency_" + str(sampleRate) + pdfFilenameSuffix +".pdf") #output this pdf file
|
cannam@140
|
23
|
cannam@140
|
24
|
cannam@140
|
25 def loadCsvData( dataFileName ):
|
cannam@140
|
26 params= ""
|
cannam@140
|
27 inputDevice = ""
|
cannam@140
|
28 outputDevice = ""
|
cannam@140
|
29
|
cannam@140
|
30 startLines = file(dataFileName).readlines(1024)
|
cannam@140
|
31 for line in startLines:
|
cannam@140
|
32 if "output device" in line:
|
cannam@140
|
33 outputDevice = line.strip(" \t\n\r#")
|
cannam@140
|
34 if "input device" in line:
|
cannam@140
|
35 inputDevice = line.strip(" \t\n\r#")
|
cannam@140
|
36 params = startLines[0].strip(" \t\n\r#")
|
cannam@140
|
37
|
cannam@140
|
38 data = numpy.loadtxt(dataFileName, delimiter=",", skiprows=4).transpose()
|
cannam@140
|
39
|
cannam@140
|
40 class R(object): pass
|
cannam@140
|
41 result = R()
|
cannam@140
|
42 result.params = params
|
cannam@140
|
43 for s in params.split(','):
|
cannam@140
|
44 if "sample rate" in s:
|
cannam@140
|
45 result.sampleRate = s
|
cannam@140
|
46
|
cannam@140
|
47 result.inputDevice = inputDevice
|
cannam@140
|
48 result.outputDevice = outputDevice
|
cannam@140
|
49 result.suggestedLatency = data[0]
|
cannam@140
|
50 result.halfDuplexOutputLatency = data[1]
|
cannam@140
|
51 result.halfDuplexInputLatency = data[2]
|
cannam@140
|
52 result.fullDuplexOutputLatency = data[3]
|
cannam@140
|
53 result.fullDuplexInputLatency = data[4]
|
cannam@140
|
54 return result;
|
cannam@140
|
55
|
cannam@140
|
56
|
cannam@140
|
57 def setFigureTitleAndAxisLabels( framesPerBufferString ):
|
cannam@140
|
58 title("PortAudio suggested (requested) vs. resulting (reported) stream latency\n" + framesPerBufferString)
|
cannam@140
|
59 ylabel("PaStreamInfo::{input,output}Latency (s)")
|
cannam@140
|
60 xlabel("Pa_OpenStream suggestedLatency (s)")
|
cannam@140
|
61 grid(True)
|
cannam@140
|
62 legend(loc="upper left")
|
cannam@140
|
63
|
cannam@140
|
64 def setDisplayRangeSeconds( maxSeconds ):
|
cannam@140
|
65 xlim(0, maxSeconds)
|
cannam@140
|
66 ylim(0, maxSeconds)
|
cannam@140
|
67
|
cannam@140
|
68
|
cannam@140
|
69 # run the test with different frames per buffer values:
|
cannam@140
|
70
|
cannam@140
|
71 compositeTestFramesPerBufferValues = [0]
|
cannam@140
|
72 # powers of two
|
cannam@140
|
73 for i in range (1,11):
|
cannam@140
|
74 compositeTestFramesPerBufferValues.append( pow(2,i) )
|
cannam@140
|
75
|
cannam@140
|
76 # multiples of 50
|
cannam@140
|
77 for i in range (1,20):
|
cannam@140
|
78 compositeTestFramesPerBufferValues.append( i * 50 )
|
cannam@140
|
79
|
cannam@140
|
80 # 10ms buffer sizes
|
cannam@140
|
81 compositeTestFramesPerBufferValues.append( 441 )
|
cannam@140
|
82 compositeTestFramesPerBufferValues.append( 882 )
|
cannam@140
|
83
|
cannam@140
|
84 # large primes
|
cannam@140
|
85 #compositeTestFramesPerBufferValues.append( 39209 )
|
cannam@140
|
86 #compositeTestFramesPerBufferValues.append( 37537 )
|
cannam@140
|
87 #compositeTestFramesPerBufferValues.append( 26437 )
|
cannam@140
|
88
|
cannam@140
|
89 individualPlotFramesPerBufferValues = [0,64,128,256,512] #output separate plots for these
|
cannam@140
|
90
|
cannam@140
|
91 isFirst = True
|
cannam@140
|
92
|
cannam@140
|
93 for framesPerBuffer in compositeTestFramesPerBufferValues:
|
cannam@140
|
94 commandString = testExeName + " " + str(inputDeviceIndex) + " " + str(outputDeviceIndex) + " " + str(sampleRate) + " " + str(framesPerBuffer) + ' > ' + dataFileName
|
cannam@140
|
95 print commandString
|
cannam@140
|
96 os.system(commandString)
|
cannam@140
|
97
|
cannam@140
|
98 d = loadCsvData(dataFileName)
|
cannam@140
|
99
|
cannam@140
|
100 if isFirst:
|
cannam@140
|
101 figure(1) # title sheet
|
cannam@140
|
102 gcf().text(0.1, 0.0,
|
cannam@140
|
103 "patest_suggested_vs_streaminfo_latency\n%s\n%s\n%s\n"%(d.inputDevice,d.outputDevice,d.sampleRate))
|
cannam@140
|
104 pdfFile.savefig()
|
cannam@140
|
105
|
cannam@140
|
106
|
cannam@140
|
107 figure(2) # composite plot, includes all compositeTestFramesPerBufferValues
|
cannam@140
|
108
|
cannam@140
|
109 if isFirst:
|
cannam@140
|
110 plot( d.suggestedLatency, d.suggestedLatency, label="Suggested latency" )
|
cannam@140
|
111
|
cannam@140
|
112 plot( d.suggestedLatency, d.halfDuplexOutputLatency )
|
cannam@140
|
113 plot( d.suggestedLatency, d.halfDuplexInputLatency )
|
cannam@140
|
114 plot( d.suggestedLatency, d.fullDuplexOutputLatency )
|
cannam@140
|
115 plot( d.suggestedLatency, d.fullDuplexInputLatency )
|
cannam@140
|
116
|
cannam@140
|
117 if framesPerBuffer in individualPlotFramesPerBufferValues: # individual plots
|
cannam@140
|
118 figure( 3 + individualPlotFramesPerBufferValues.index(framesPerBuffer) )
|
cannam@140
|
119
|
cannam@140
|
120 plot( d.suggestedLatency, d.suggestedLatency, label="Suggested latency" )
|
cannam@140
|
121 plot( d.suggestedLatency, d.halfDuplexOutputLatency, label="Half-duplex output latency" )
|
cannam@140
|
122 plot( d.suggestedLatency, d.halfDuplexInputLatency, label="Half-duplex input latency" )
|
cannam@140
|
123 plot( d.suggestedLatency, d.fullDuplexOutputLatency, label="Full-duplex output latency" )
|
cannam@140
|
124 plot( d.suggestedLatency, d.fullDuplexInputLatency, label="Full-duplex input latency" )
|
cannam@140
|
125
|
cannam@140
|
126 if framesPerBuffer == 0:
|
cannam@140
|
127 framesPerBufferText = "paFramesPerBufferUnspecified"
|
cannam@140
|
128 else:
|
cannam@140
|
129 framesPerBufferText = str(framesPerBuffer)
|
cannam@140
|
130 setFigureTitleAndAxisLabels( "user frames per buffer: "+str(framesPerBufferText) )
|
cannam@140
|
131 setDisplayRangeSeconds(2.2)
|
cannam@140
|
132 pdfFile.savefig()
|
cannam@140
|
133 setDisplayRangeSeconds(0.1)
|
cannam@140
|
134 setFigureTitleAndAxisLabels( "user frames per buffer: "+str(framesPerBufferText)+" (detail)" )
|
cannam@140
|
135 pdfFile.savefig()
|
cannam@140
|
136
|
cannam@140
|
137 isFirst = False
|
cannam@140
|
138
|
cannam@140
|
139 figure(2)
|
cannam@140
|
140 setFigureTitleAndAxisLabels( "composite of frames per buffer values:\n"+str(compositeTestFramesPerBufferValues) )
|
cannam@140
|
141 setDisplayRangeSeconds(2.2)
|
cannam@140
|
142 pdfFile.savefig()
|
cannam@140
|
143 setDisplayRangeSeconds(0.1)
|
cannam@140
|
144 setFigureTitleAndAxisLabels( "composite of frames per buffer values:\n"+str(compositeTestFramesPerBufferValues)+" (detail)" )
|
cannam@140
|
145 pdfFile.savefig()
|
cannam@140
|
146
|
cannam@140
|
147 pdfFile.close()
|
cannam@140
|
148
|
cannam@140
|
149 #uncomment this to display interactively, otherwise we just output a pdf
|
cannam@140
|
150 #show()
|