e3bfebc7992515368451399efbdb11b5e4a8ca5d
[aubio.git] / python / aubio / gnuplot.py
1 """Copyright (C) 2004 Paul Brossier <piem@altern.org>
2 print aubio.__LICENSE__ for the terms of use
3 """
4
5 __LICENSE__ = """\
6          Copyright (C) 2004 Paul Brossier <piem@altern.org>
7
8          This program is free software; you can redistribute it and/or modify
9          it under the terms of the GNU General Public License as published by
10          the Free Software Foundation; either version 2 of the License, or
11          (at your option) any later version.
12
13          This program is distributed in the hope that it will be useful,
14          but WITHOUT ANY WARRANTY; without even the implied warranty of
15          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16          GNU General Public License for more details.
17
18          You should have received a copy of the GNU General Public License
19          along with this program; if not, write to the Free Software
20          Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 """
22
23 __notesheight = 0.25
24
25 from numarray import *
26 import Gnuplot, Gnuplot.funcutils
27
28 def plotnote(la,title=None) :
29         if la[0,:].size() == 3:
30                 d = plotnote_withends(la, plot_title=title)
31         else: 
32             # scale data if in freq (for REF.txt files)
33             if max(la[:,1] > 128 ):
34                 print "scaling frequency data to midi range"
35                 la[:,1] /= 6.875
36                 la[:,1] = log(la[:,1])/0.6931
37                 la[:,1] *= 12
38                 la[:,1] -= 3
39             d = plotnote_withoutends(la, plot_title=title)
40         return d
41
42 def plotnote_multi(lalist,title=None,fileout=None) :
43         d=list()
44         for i in range(len(lalist)):
45             d.append(plotnote(lalist[i], title=title))
46         return d
47        
48
49 def plotnote_withends(la,plot_title=None) :
50         d=[]
51         x_widths = array(la[:,1]-la[:,0])/2.
52         d.append(Gnuplot.Data(
53                 la[:,0]+x_widths,               # x centers
54                 la[:,2],                        # y centers
55                 x_widths,                       # x errors
56                 __notesheight*ones(len(la)),    # y errors
57                 title=plot_title,with=('boxxyerrorbars fs 3')))
58         return d
59
60
61 def plotnote_withoutends(la,plot_title=None) :
62         """ bug: fails drawing last note """
63         d=[]
64         x_widths = array(la[1:,0]-la[:-1,0])/2;
65         d.append(Gnuplot.Data(
66                 la[:-1,0]+x_widths,             # x centers
67                 la[:-1,1],                      # y centers
68                 x_widths,                       # x errors
69                 __notesheight*ones(len(la)-1),  # y errors
70                 title=plot_title,with=('boxxyerrorbars fs 3')))
71         return d
72
73 def plotnote_do(d,fileout=None):
74     g = Gnuplot.Gnuplot(debug=1, persist=1)
75     g.gnuplot('set style fill solid border 1; \
76     set size ratio 1/6; \
77     set boxwidth 0.9 relative; \
78     set mxtics 2.5; \
79     set mytics 2.5; \
80     set xtics 5; \
81     set ytics 1; \
82     set grid xtics ytics mxtics mytics')
83
84     g.xlabel('Time (s)')
85     g.ylabel('Midi pitch')
86     # do the plot
87     #g.gnuplot('set multiplot')
88     #for i in d:
89     g.plot(d[0])
90     #g.gnuplot('set nomultiplot') 
91     if fileout != None:
92         g.hardcopy(fileout, enhanced=1, color=0)
93
94 def audio_to_array(filename):
95         import aubio.aubioclass
96         hopsize  = 2048
97         filei    = aubio.aubioclass.sndfile(filename)
98         framestep = 1/(filei.samplerate()+0.)
99         channels = filei.channels()
100         myvec    = aubio.aubioclass.fvec(hopsize,channels)
101         data = []
102         readsize = hopsize
103         while (readsize==hopsize):
104                 readsize = filei.read(hopsize,myvec)
105                 #for i in range(channels):
106                 i = 0
107                 curpos = 0
108                 while (curpos < readsize):
109                         data.append(myvec.get(curpos,i))
110                         curpos+=1
111         time = arange(len(data))*framestep
112         return time,data
113
114 def plot_audio(filenames, fileout=None, start=0, end=None, noaxis=None):
115         g = Gnuplot.Gnuplot(debug=1, persist=1)
116         d = []
117         todraw = len(filenames)
118         xorig = 0.
119         xsize = 1./todraw
120         g.gnuplot('set multiplot;')
121         while (len(filenames)):
122                 d.append(plot_audio_make(filenames.pop(0)))
123                 if not noaxis and todraw==1:
124                         g.xlabel('Time (s)')
125                         g.ylabel('Amplitude')
126                 g.gnuplot('set size %f,1.;' % (xsize) )
127                 g.gnuplot('set origin %f,0.;' % (xorig) )
128                 g.gnuplot('set style data lines; \
129                         set yrange [-1.:1.]; \
130                         set xrange [0:%f]' % b[-1]) 
131                 g.plot(d.pop(0))
132                 xorig += 1./todraw
133         g.gnuplot('unset multiplot;')
134         if fileout != None:
135                 g.hardcopy(fileout, enhanced=1, color=0)
136
137 def make_audio_plot(time,data,maxpoints=10000):
138         """ create gnuplot plot from an audio file """
139         length = len(time)
140         downsample = length/maxpoints
141         if downsample == 0: downsample = 1
142         x = array(time).resize(length)[0:-1:downsample]
143         y = array(data).resize(length)[0:-1:downsample]
144         return Gnuplot.Data(x,y,with='lines')
145
146
147 def plot_onsets(filename, onsets, ofunc, samplerate=44100., hopsize=512, outplot=None):
148         import aubio.txtfile
149         import os.path
150         import numarray
151         from aubio.onsetcompare import onset_roc
152
153         if len(onsets) == 0: onsets = [0.];
154
155         # onset detection function 
156         downtime = (hopsize/samplerate)*numarray.arange(len(ofunc))
157         d = Gnuplot.Data(downtime,ofunc,with='lines') 
158
159         # detected onsets
160         x1 = (hopsize/samplerate)*numarray.array(onsets)
161         y1 = max(ofunc)*numarray.ones(len(onsets))
162         e = Gnuplot.Data(x1,-y1,with='impulses') 
163         e2= Gnuplot.Data(x1,y1,with='impulses') 
164
165         # check if datafile exists truth
166         datafile = filename.replace('.wav','.txt')
167         if not os.path.isfile(datafile):
168                 title = "truth file not found"
169                 t = Gnuplot.Data(0,0,with='impulses') 
170         else:
171                 t_onsets = aubio.txtfile.read_datafile(datafile)
172                 y2 = max(ofunc)*numarray.ones(len(t_onsets))
173                 x2 = numarray.array(t_onsets).resize(len(t_onsets))
174                 t = Gnuplot.Data(x2,y2,with='impulses') 
175                 
176                 tol = 0.050 
177
178                 orig, missed, merged, expc, bad, doubled = \
179                         onset_roc(x2,x1,tol)
180                 title = "GD %2.3f%% FP %2.3f%%" % \
181                         ((100*float(orig-missed-merged)/(orig)),
182                          (100*float(bad+doubled)/(orig)))
183                 #print  orig, missed, merged, expc, bad, doubled
184                 #print "GD %2.8f\t"        % (100*float(orig-missed-merged)/(orig)),
185                 #print "FP %2.8f\t"        % (100*float(bad+doubled)/(orig))       , 
186                 #print "GD-merged %2.8f\t" % (100*float(orig-missed)/(orig))       , 
187                 #print "FP-pruned %2.8f\t" % (100*float(bad)/(orig))                
188
189         # audio data
190         time,data = audio_to_array(filename)
191         f = make_audio_plot(time,data)
192
193         # prepare the plot
194         g = Gnuplot.Gnuplot(debug=1, persist=1)
195         if outplot:
196                 extension = outplot.split('.')[-1]
197                 if extension == 'ps': extension = 'postscript'
198                 g('set terminal %s' % extension)
199                 g('set output \'%s\'' % outplot)
200
201         g('set title \'%s %s\'' % (filename,title))
202
203         g('set multiplot')
204
205         # hack to align left axis
206         g('set lmargin 15')
207
208         # plot waveform and onsets
209         g('set size 1,0.3')
210         g('set origin 0,0.7')
211         g('set xrange [0:%f]' % max(time)) 
212         g('set yrange [-1:1]') 
213         g.ylabel('amplitude')
214         g.plot(f,e,t)
215         
216         g('unset title')
217
218         # plot onset detection function
219         g('set size 1,0.7')
220         g('set origin 0,0')
221         g('set xrange [0:%f]' % (hopsize/samplerate*len(ofunc)))
222         g('set yrange [0:%f]' % (max(ofunc)*1.01))
223         g.xlabel('time')
224         g.ylabel('onset detection value')
225         g.plot(d,e2)
226
227         g('unset multiplot')
228
229
230 def plot_pitch(filename, pitch, samplerate=44100., hopsize=512, outplot=None):
231         import aubio.txtfile
232         import os.path
233         import numarray
234
235         # onset detection function 
236         downtime = (hopsize/samplerate)*numarray.arange(len(pitch))
237         d = Gnuplot.Data(downtime,pitch,with='lines') 
238
239         # check if datafile exists truth
240         datafile = filename.replace('.wav','.txt')
241         if not os.path.isfile(datafile):
242                 title = "truth file not found"
243                 t = Gnuplot.Data(0,0,with='impulses') 
244         else:
245                 title = "truth file plotting not implemented yet"
246                 t = Gnuplot.Data(0,0,with='impulses') 
247                 #times,pitch = aubio.txtfile.read_datafile(datafile)
248                 #t = Gnuplot.Data(times,pitch,with='lines') 
249                 
250                 #orig, missed, merged, expc, bad, doubled = \
251                 #        onset_roc(x2,x1,tol)
252                 #title = "GD %2.3f%% FP %2.3f%%" % \
253                 #        ((100*float(orig-missed-merged)/(orig)),
254                 #         (100*float(bad+doubled)/(orig)))
255                 #print  orig, missed, merged, expc, bad, doubled
256                 #print "GD %2.8f\t"        % (100*float(orig-missed-merged)/(orig)),
257                 #print "FP %2.8f\t"        % (100*float(bad+doubled)/(orig))       , 
258                 #print "GD-merged %2.8f\t" % (100*float(orig-missed)/(orig))       , 
259                 #print "FP-pruned %2.8f\t" % (100*float(bad)/(orig))                
260
261         # audio data
262         time,data = audio_to_array(filename)
263         f = make_audio_plot(time,data)
264
265         # prepare the plot
266         g = Gnuplot.Gnuplot(debug=1, persist=1)
267         if outplot:
268                 extension = outplot.split('.')[-1]
269                 if extension == 'ps': extension = 'postscript'
270                 g('set terminal %s' % extension)
271                 g('set output \'%s\'' % outplot)
272
273         g('set title \'%s %s\'' % (filename,title))
274
275         g('set multiplot')
276
277         # hack to align left axis
278         g('set lmargin 15')
279
280         # plot waveform and onsets
281         g('set size 1,0.3')
282         g('set origin 0,0.7')
283         g('set xrange [0:%f]' % max(time)) 
284         g('set yrange [-1:1]') 
285         g.ylabel('amplitude')
286         g.plot(f)
287         
288         g('unset title')
289
290         # plot onset detection function
291         g('set size 1,0.7')
292         g('set origin 0,0')
293         g('set xrange [0:%f]' % (hopsize/samplerate*len(pitch)))
294         g('set yrange [0:%f]' % (max(pitch)*1.01))
295         g.xlabel('time')
296         g.ylabel('frequency (Hz)')
297         g.plot(d,t)
298
299         g('unset multiplot')