merged aubioplot-onsets into aubiocut, added some more options
authorPaul Brossier <piem@altern.org>
Mon, 30 May 2005 04:44:52 +0000 (04:44 +0000)
committerPaul Brossier <piem@altern.org>
Mon, 30 May 2005 04:44:52 +0000 (04:44 +0000)
python/README
python/aubio/aubioclass.py
python/aubio/gnuplot.py
python/aubiocut
python/aubioplot-onset [deleted file]

index 4b03d0d..ff0bf8a 100644 (file)
@@ -1,5 +1,6 @@
 Here you will find some examples of python scripts and some evaluation
 routines. The python interface for libaubio is generated using Swig.
 
-To have it working before installation, set LD_LIBRARY_PATH as:
-LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib:../src/.libs
+To have it working before installation, you will need to set LD_LIBRARY_PATH
+# export LD_LIBRARY_PATH=../src/.libs:../ext/.libs
+for instance, to run the python script from within aubio/python/. 
index ab90020..f2d0c15 100644 (file)
@@ -73,7 +73,7 @@ class peakpick:
 
 class onsetpick:
     """ superclass for aubio_pvoc + aubio_onsetdetection + aubio_peakpicker """
-    def __init__(self,bufsize,hopsize,channels,myvec,threshold,mode='dual'):
+    def __init__(self,bufsize,hopsize,channels,myvec,threshold,mode='dual',derivate=False):
         self.myfft    = cvec(bufsize,channels)
         self.pv       = pvoc(bufsize,hopsize,channels)
         if mode in [complexdomain,hfc,phase,energy,specdiff]  :
@@ -86,6 +86,8 @@ class onsetpick:
                 self.myonset2 = fvec(1,channels)
         self.mode     = mode
         self.pp       = peakpick(float(threshold))
+        self.derivate = derivate
+        self.oldval   = 0.
 
     def do(self,myvec): 
         self.pv.do(myvec,self.myfft)
@@ -93,15 +95,23 @@ class onsetpick:
         if self.mode == 'dual':
                 self.myod2.do(self.myfft,self.myonset2)
                 self.myonset.set(self.myonset.get(0,0)*self.myonset2.get(0,0),0,0)
+        if self.derivate:
+                val         = self.myonset.get(0,0)
+                dval        = val - self.oldval
+                self.oldval = val
+                if dval > 0: self.myonset.set(dval,0,0)
+                else:  self.myonset.set(0.,0,0)
         return self.pp.do(self.myonset),self.myonset.get(0,0)
 
-def getonsets(filein,threshold=0.2,silence=-70.,bufsize=1024,hopsize=512,mode='dual',localmin=False,storefunc=False):
+def getonsets(filein,threshold=0.2,silence=-70.,bufsize=1024,hopsize=512,
+                mode='dual',localmin=False,storefunc=False,derivate=False):
         frameread = 0
         filei     = sndfile(filein)
         channels  = filei.channels()
         myvec     = fvec(hopsize,channels)
         readsize  = filei.read(hopsize,myvec)
-        opick     = onsetpick(bufsize,hopsize,channels,myvec,threshold,mode=mode)
+        opick     = onsetpick(bufsize,hopsize,channels,myvec,threshold,
+                         mode=mode,derivate=derivate)
         mylist    = list()
         if localmin:
                 ovalist   = [0., 0., 0., 0., 0.]
@@ -113,7 +123,8 @@ def getonsets(filein,threshold=0.2,silence=-70.,bufsize=1024,hopsize=512,mode='d
                 if (aubio_silence_detection(myvec(),silence)):
                         isonset=0
                 if localmin:
-                        ovalist.append(val)
+                        if val > 0: ovalist.append(val)
+                        else: ovalist.append(0)
                         ovalist.pop(0)
                 if storefunc:
                         ofunclist.append(val)
@@ -135,7 +146,7 @@ def getonsets(filein,threshold=0.2,silence=-70.,bufsize=1024,hopsize=512,mode='d
         if storefunc: return mylist, ofunclist
         else: return mylist
 
-def cutfile(filein,slicetimes,zerothres=0.002,bufsize=1024,hopsize=512):
+def cutfile(filein,slicetimes,zerothres=0.008,bufsize=1024,hopsize=512):
     frameread = 0
     readsize  = hopsize 
     filei     = sndfile(filein)
@@ -153,18 +164,18 @@ def cutfile(filein,slicetimes,zerothres=0.002,bufsize=1024,hopsize=512):
             # write up to 1st zero crossing
             zerocross = 0
             while ( abs( myvec.get(zerocross,0) ) > zerothres ):
-               zerocross += 1
+                zerocross += 1
             writesize = fileo.write(zerocross,myvec)
             fromcross = 0
             while (zerocross < readsize):
-               for i in range(channels):
-                       mycopy.set(myvec.get(zerocross,i),fromcross,i)
-               fromcross += 1
-               zerocross += 1
+                for i in range(channels):
+                    mycopy.set(myvec.get(zerocross,i),fromcross,i)
+                    fromcross += 1
+                    zerocross += 1
             del fileo
             fileo = sndfile("%s%s%f%s%s" % 
-               (filein.split(".")[0].split("/")[-1],".",
-               frameread*framestep,".",filein.split(".")[-1]),model=filei)
+                (filein.split(".")[0].split("/")[-1],".",
+                frameread*framestep,".",filein.split(".")[-1]),model=filei)
             writesize = fileo.write(fromcross,mycopy)
         else:
             writesize = fileo.write(readsize,myvec)
index 33041d8..d62d513 100644 (file)
@@ -136,10 +136,90 @@ def plot_audio(filenames, fileout=None, start=0, end=None, noaxis=None):
 
 def make_audio_plot(time,data,maxpoints=10000):
        """ create gnuplot plot from an audio file """
-        import numarray
         length = len(time)
        downsample = length/maxpoints
         if downsample == 0: downsample = 1
-        x = numarray.array(time).resize(length)[0:-1:downsample]
-        y = numarray.array(data).resize(length)[0:-1:downsample]
+        x = array(time).resize(length)[0:-1:downsample]
+        y = array(data).resize(length)[0:-1:downsample]
        return Gnuplot.Data(x,y,with='lines')
+
+
+def plot_onsets(filename, onsets, ofunc, samplerate=44100., hopsize=512, outplot=None):
+        import aubio.txtfile
+        import os.path
+        import numarray
+        from aubio.onsetcompare import onset_roc
+
+        # onset detection function 
+        downtime = (hopsize/samplerate)*numarray.arange(len(ofunc))
+        d = Gnuplot.Data(downtime,ofunc,with='lines') 
+
+        # detected onsets
+        x1 = (hopsize/samplerate)*numarray.array(onsets)
+        y1 = max(ofunc)*numarray.ones(len(onsets))
+        e = Gnuplot.Data(x1,-y1,with='impulses') 
+        e2= Gnuplot.Data(x1,y1,with='impulses') 
+
+        # check if datafile exists truth
+        datafile = filename.replace('.wav','.txt')
+        if not os.path.isfile(datafile):
+                title = "truth file not found"
+                t = Gnuplot.Data(0,0,with='impulses') 
+        else:
+                t_onsets = aubio.txtfile.read_datafile(datafile)
+                y2 = max(ofunc)*numarray.ones(len(t_onsets))
+                x2 = numarray.array(t_onsets).resize(len(t_onsets))
+                t = Gnuplot.Data(x2,y2,with='impulses') 
+                
+                tol = 0.050 
+
+                orig, missed, merged, expc, bad, doubled = \
+                        onset_roc(x2,x1,tol)
+                title = "GD %2.3f%% FP %2.3f%%" % \
+                        ((100*float(orig-missed-merged)/(orig)),
+                         (100*float(bad+doubled)/(orig)))
+                #print  orig, missed, merged, expc, bad, doubled
+                #print "GD %2.8f\t"        % (100*float(orig-missed-merged)/(orig)),
+                #print "FP %2.8f\t"        % (100*float(bad+doubled)/(orig))       , 
+                #print "GD-merged %2.8f\t" % (100*float(orig-missed)/(orig))       , 
+                #print "FP-pruned %2.8f\t" % (100*float(bad)/(orig))                
+
+        # audio data
+        time,data = audio_to_array(filename)
+        f = make_audio_plot(time,data)
+
+        # prepare the plot
+        g = Gnuplot.Gnuplot(debug=1, persist=1)
+        if outplot:
+                extension = outplot.split('.')[-1]
+                if extension == 'ps': extension = 'postscript'
+                g('set terminal %s' % extension)
+                g('set output \'%s\'' % outplot)
+
+        g('set title \'%s %s\'' % (filename,title))
+
+        g('set multiplot')
+
+        # hack to align left axis
+        g('set lmargin 15')
+
+        # plot waveform and onsets
+        g('set size 1,0.3')
+        g('set origin 0,0.7')
+        g('set xrange [0:%f]' % max(time)) 
+        g('set yrange [-1:1]') 
+        g.ylabel('amplitude')
+        g.plot(f,e,t)
+        
+        g('unset title')
+
+        # plot onset detection function
+        g('set size 1,0.7')
+        g('set origin 0,0')
+        g('set xrange [0:%f]' % (hopsize/samplerate*len(ofunc)))
+        g('set yrange [0:%f]' % (max(ofunc)*1.01))
+        g.xlabel('time')
+        g.ylabel('onset detection value')
+        g.plot(d,e2)
+
+        g('unset multiplot')
index 07125e2..205cc71 100755 (executable)
@@ -33,7 +33,7 @@ def parse_args():
                           help="input sound file")
         parser.add_option("-m","--mode", action="callback", 
                           callback=check_mode, dest="mode", default='dual', 
-                          help="onsetdetection mode [default=dual] \
+                          help="onset detection mode [default=dual] \
                           complexdomain|hfc|phase|specdiff|energy|dual")
         parser.add_option("-B","--bufsize",
                           action="store", dest="bufsize", default=1024, 
@@ -51,8 +51,9 @@ def parse_args():
                           action="store", dest="mintol", default=0.048, 
                           help="minimum inter onset interval [default=0.048]")
         parser.add_option("-D","--delay",
-                          action="store", dest="delay", default=0.022, 
-                          help="number of seconds to take back [default=0.022]")
+                          action="store", dest="delay",  
+                          help="number of seconds to take back [default=system]\
+                          default system delay is 2*hopsize/samplerate")
         parser.add_option("-L","--localmin",
                           action="store_true", dest="localmin", default=False, 
                           help="use local minima after peak detection")
@@ -60,23 +61,23 @@ def parse_args():
                           action="store_true", dest="cut", default=False,
                           help="cut input sound file at detected labels \
                           best used with option -L")
+        parser.add_option("-d","--derivate",
+                          action="store_true", dest="derivate", default=False, 
+                          help="derivate onset detection function")
         # to be implemented
-        # plotting functions
-        parser.add_option("-d","--derivative",
-                          action="store_true", dest="derivative", default=False, 
-                          help="NOT IMPLEMENTED derivate onset detection function")
-        parser.add_option("-p","--plot",
-                          action="store_true", dest="doplot", default=False, 
-                          help="NOT IMPLEMENTED draw plot")
-        parser.add_option("-O","--outplot",
-                          action="store", dest="output-plot", default=None, 
-                          help="NOT IMPLEMENTED save plot to output.{ps,png}")
         parser.add_option("-z","--zerocross",
                           action="store_true", dest="zerocross", default=False, 
                           help="NOT IMPLEMENTED zero crossing matching")
         parser.add_option("-b","--beat",
                           action="store_true", dest="beat", default=False,
                           help="NOT IMPLEMENTED output beat locations")
+        # plotting functions
+        parser.add_option("-p","--plot",
+                          action="store_true", dest="plot", default=False, 
+                          help="draw plot")
+        parser.add_option("-O","--outplot",
+                          action="store", dest="outplot", default=None, 
+                          help="save plot to output.{ps,png}")
         parser.add_option("-v","--verbose",
                           action="store_true", dest="verbose", default=False,
                           help="make lots of noise [default]")
@@ -99,14 +100,22 @@ step       = float(samplerate)/float(hopsize)
 threshold  = float(options.threshold)
 silence    = float(options.silence)
 mintol     = float(options.mintol)*step
-delay      = float(options.delay)
+# default take back system delay
+if options.delay: delay = float(options.delay)
+else:             delay = 2./step
 
 if options.beat:
         #onsets = getbeats(filename,threshold,silence,mode=options.mode)
         exit("not implemented yet")
+elif options.plot:
+        onsets, ofunc = getonsets(filename,threshold,silence,
+                mode=options.mode,localmin=options.localmin,
+                derivate=options.derivate,
+                bufsize=bufsize,hopsize=hopsize,storefunc=True)
 else:
         onsets = getonsets(filename,threshold,silence,
                 mode=options.mode,localmin=options.localmin,
+                derivate=options.derivate,
                 bufsize=bufsize,hopsize=hopsize)
 
 # take back system delay
@@ -128,5 +137,10 @@ if mintol > 0:
 if options.verbose:
         for i in onsets: print "%f" % (i/step)
 
+if options.plot:
+        from aubio.gnuplot import plot_onsets
+        plot_onsets(filename, onsets, ofunc, 
+                samplerate=samplerate, hopsize=hopsize, outplot=options.outplot)
+
 if options.cut:
         cutfile(filename,onsets,bufsize=bufsize,hopsize=hopsize)
diff --git a/python/aubioplot-onset b/python/aubioplot-onset
deleted file mode 100755 (executable)
index f43e57b..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-#! /usr/bin/python
-
-import sys
-import numarray
-import Gnuplot, Gnuplot.funcutils
-from aubio.aubioclass import *
-import aubio.gnuplot
-import aubio.txtfile
-from aubio.onsetcompare import onset_roc
-
-
-usage = "usage: %s [options] soundfile" % sys.argv[0]
-
-def parse_args():
-        from optparse import OptionParser
-        parser = OptionParser(usage=usage)
-        parser.add_option("-v","--verbose",
-                          action="store_true", dest="verbose", default=False,
-                          help="make lots of noise")
-        parser.add_option("-q","--quiet",
-                          action="store_false", dest="verbose", default=True, 
-                          help="be quiet [default]")
-        parser.add_option("-t","--threshold",
-                          action="store", dest="threshold", default=0.3, 
-                          help="onset detection threshold [default=0.3]")
-        parser.add_option("-s","--silence",
-                          action="store", dest="silence", default=-70, 
-                          help="silence [default=-70]")
-        def check_mode(option, opt, value, parser):
-                nvalue = parser.rargs[0]
-                if   nvalue == 'complexdomain' : setattr(parser.values, option.dest, complexdomain)
-                elif nvalue == 'hfc'           : setattr(parser.values, option.dest, hfc)
-                elif nvalue == 'phase'         : setattr(parser.values, option.dest, phase)
-                elif nvalue == 'specdiff'      : setattr(parser.values, option.dest, specdiff)
-                elif nvalue == 'energy'        : setattr(parser.values, option.dest, energy)
-                elif nvalue == 'dual'          : setattr(parser.values, option.dest, 'dual')
-        parser.add_option("-m","--mode",
-                          action="callback", callback=check_mode, dest="mode", default='dual', 
-                          help="onsetdetection mode [default=dual]")
-        parser.add_option("-o","--outplot",
-                          action="store", dest="outplot", default=None, 
-                          help="be quiet [default=None]")
-        (options, args) = parser.parse_args()
-        if not len(args): 
-                 print "no file name given\n", usage
-                 sys.exit(1)
-        return options, args
-
-options, args = parse_args()
-
-filename  = args[0] #FIXME should move to optparse
-threshold = float(options.threshold)
-silence   = float(options.silence)
-
-print options.mode
-onsets, ofunc   = getonsetsfunc(filename,threshold,silence,mode=options.mode)
-
-g = Gnuplot.Gnuplot(debug=1, persist=1)
-
-if options.outplot:
-        extension = options.outplot.split('.')[-1]
-        if extension == 'ps': extension = 'postscript'
-        g('set terminal %s' % extension)
-        g('set output \'%s\'' % options.outplot)
-
-g('set multiplot')
-
-# onset detection function 
-downtime = (512./44100.)*numarray.arange(len(ofunc))
-d = Gnuplot.Data(downtime,ofunc,with='lines') 
-
-# detected onsets
-x1 = (512./44100.)*numarray.array(onsets)
-y1 = max(ofunc)*numarray.ones(len(onsets))
-e = Gnuplot.Data(x1,-y1,with='impulses') 
-e2= Gnuplot.Data(x1,y1,with='impulses') 
-
-# truth
-import os.path
-datafile = filename.replace('.wav','.txt')
-if not os.path.isfile(datafile):
-        print "truth file not found"
-        t = Gnuplot.Data(0,0,with='impulses') 
-else:
-        t_onsets = aubio.txtfile.read_datafile(datafile)
-        y2 = max(ofunc)*numarray.ones(len(t_onsets))
-        x2 = numarray.array(t_onsets).resize(len(t_onsets))
-        t = Gnuplot.Data(x2,y2,with='impulses') 
-        
-        eps = 4*0.012 
-
-        orig, missed, merged, expc, bad, doubled = \
-                onset_roc(x2,x1,eps)
-        print  orig, missed, merged, expc, bad, doubled
-        print "GD %2.8f\t"        % (100*float(orig-missed-merged)/(orig)),
-        print "FP %2.8f\t"        % (100*float(bad+doubled)/(orig))       , 
-        print "GD-merged %2.8f\t" % (100*float(orig-missed)/(orig))       , 
-        print "FP-pruned %2.8f\t" % (100*float(bad)/(orig))                
-
-# audio data
-time,data = aubio.gnuplot.audio_to_array(filename)
-f = aubio.gnuplot.make_audio_plot(time,data)
-
-# hack to align left axis
-g('set lmargin 15')
-
-g('set size 1,0.3')
-g('set origin 0,0.7')
-g('set xrange [0:%f]' % max(time)) 
-g('set yrange [-1:1]') 
-g.ylabel('amplitude')
-g.plot(f,e,t)
-
-g('set size 1,0.7')
-g('set origin 0,0')
-g('set xrange [0:%f]' % (512./44100.*len(ofunc)))
-g('set yrange [0:%f]' % (max(ofunc)*1.01))
-g.xlabel('time')
-g.ylabel('onset detection value')
-
-g.plot(d,e2)
-
-g('unset multiplot')
-