From 80c0417c84d6f98064b7aa2ac5d9b22c496e68df Mon Sep 17 00:00:00 2001 From: Paul Brossier Date: Mon, 30 May 2005 04:44:52 +0000 Subject: [PATCH] merged aubioplot-onsets into aubiocut, added some more options --- python/README | 5 +- python/aubio/aubioclass.py | 35 +++++++---- python/aubio/gnuplot.py | 86 ++++++++++++++++++++++++- python/aubiocut | 42 ++++++++----- python/aubioplot-onset | 124 ------------------------------------- 5 files changed, 137 insertions(+), 155 deletions(-) delete mode 100755 python/aubioplot-onset diff --git a/python/README b/python/README index 4b03d0d3..ff0bf8a9 100644 --- a/python/README +++ b/python/README @@ -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/. diff --git a/python/aubio/aubioclass.py b/python/aubio/aubioclass.py index ab900208..f2d0c15d 100644 --- a/python/aubio/aubioclass.py +++ b/python/aubio/aubioclass.py @@ -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) diff --git a/python/aubio/gnuplot.py b/python/aubio/gnuplot.py index 33041d81..d62d5135 100644 --- a/python/aubio/gnuplot.py +++ b/python/aubio/gnuplot.py @@ -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') diff --git a/python/aubiocut b/python/aubiocut index 07125e24..205cc717 100755 --- a/python/aubiocut +++ b/python/aubiocut @@ -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 index f43e57bf..00000000 --- a/python/aubioplot-onset +++ /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') - -- 2.26.2