Showing the changes to python.old/aubio (27 of 42 files). Show all
Unified · Split
| @@ -0,0 +1,28 @@ | ||
| 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-2009 Paul Brossier <piem@aubio.org> | |
| 7 | + | |
| 8 | + This file is part of aubio. | |
| 9 | + | |
| 10 | + aubio is free software: you can redistribute it and/or modify | |
| 11 | + it under the terms of the GNU General Public License as published by | |
| 12 | + the Free Software Foundation, either version 3 of the License, or | |
| 13 | + (at your option) any later version. | |
| 14 | + | |
| 15 | + aubio is distributed in the hope that it will be useful, | |
| 16 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 17 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 18 | + GNU General Public License for more details. | |
| 19 | + | |
| 20 | + You should have received a copy of the GNU General Public License | |
| 21 | + along with aubio. If not, see <http://www.gnu.org/licenses/>. | |
| 22 | +""" | |
| 23 | + | |
| 24 | +#from aubioclass import * | |
| 25 | +#from onsetcompare import * | |
| 26 | +#from median import * | |
| 27 | +#from noteroc import * | |
| 28 | +#from txtfile import * | |
| @@ -0,0 +1,160 @@ | ||
| 1 | +from aubiowrapper import * | |
| 2 | + | |
| 3 | +class fvec: | |
| 4 | + def __init__(self,size): | |
| 5 | + self.vec = new_fvec(size) | |
| 6 | + def __call__(self): | |
| 7 | + return self.vec | |
| 8 | + def __del__(self): | |
| 9 | + del_fvec(self()) | |
| 10 | + def get(self,pos): | |
| 11 | + return fvec_read_sample(self(),pos) | |
| 12 | + def set(self,value,pos): | |
| 13 | + return fvec_write_sample(self(),value,pos) | |
| 14 | + def data(self): | |
| 15 | + return fvec_get_data(self()) | |
| 16 | + | |
| 17 | +class cvec: | |
| 18 | + def __init__(self,size): | |
| 19 | + self.vec = new_cvec(size) | |
| 20 | + def __call__(self): | |
| 21 | + return self.vec | |
| 22 | + def __del__(self): | |
| 23 | + del_cvec(self()) | |
| 24 | + def get(self,pos): | |
| 25 | + return self.get_norm(pos) | |
| 26 | + def set(self,val,pos): | |
| 27 | + self.set_norm(val,pos) | |
| 28 | + def get_norm(self,pos): | |
| 29 | + return cvec_read_norm(self(),pos) | |
| 30 | + def set_norm(self,val,pos): | |
| 31 | + cvec_write_norm(self(),val,pos) | |
| 32 | + def get_phas(self,pos): | |
| 33 | + return cvec_read_phas(self(),pos) | |
| 34 | + def set_phas(self,val,pos): | |
| 35 | + cvec_write_phas(self(),val,pos) | |
| 36 | + | |
| 37 | +class sndfile: | |
| 38 | + def __init__(self,filename,model=None): | |
| 39 | + if (model!=None): | |
| 40 | + self.file = new_aubio_sndfile_wo(model.file,filename) | |
| 41 | + else: | |
| 42 | + self.file = new_aubio_sndfile_ro(filename) | |
| 43 | + if self.file == None: | |
| 44 | + raise IOError, "failed opening file %s" % filename | |
| 45 | + def __del__(self): | |
| 46 | + if self.file != None: del_aubio_sndfile(self.file) | |
| 47 | + def info(self): | |
| 48 | + aubio_sndfile_info(self.file) | |
| 49 | + def samplerate(self): | |
| 50 | + return aubio_sndfile_samplerate(self.file) | |
| 51 | + def channels(self): | |
| 52 | + return aubio_sndfile_channels(self.file) | |
| 53 | + def read(self,nfram,vecread): | |
| 54 | + return aubio_sndfile_read_mono(self.file,nfram,vecread()) | |
| 55 | + def write(self,nfram,vecwrite): | |
| 56 | + return aubio_sndfile_write(self.file,nfram,vecwrite()) | |
| 57 | + | |
| 58 | +class pvoc: | |
| 59 | + def __init__(self,buf,hop): | |
| 60 | + self.pv = new_aubio_pvoc(buf,hop) | |
| 61 | + def __del__(self): | |
| 62 | + del_aubio_pvoc(self.pv) | |
| 63 | + def do(self,tf,tc): | |
| 64 | + aubio_pvoc_do(self.pv,tf(),tc()) | |
| 65 | + def rdo(self,tc,tf): | |
| 66 | + aubio_pvoc_rdo(self.pv,tc(),tf()) | |
| 67 | + | |
| 68 | +class onsetdetection: | |
| 69 | + """ class for aubio_specdesc """ | |
| 70 | + def __init__(self,mode,buf): | |
| 71 | + self.od = new_aubio_specdesc(mode,buf) | |
| 72 | + def do(self,tc,tf): | |
| 73 | + aubio_specdesc_do(self.od,tc(),tf()) | |
| 74 | + def __del__(self): | |
| 75 | + del_aubio_specdesc(self.od) | |
| 76 | + | |
| 77 | +class peakpick: | |
| 78 | + """ class for aubio_peakpicker """ | |
| 79 | + def __init__(self,threshold=0.1): | |
| 80 | + self.pp = new_aubio_peakpicker() | |
| 81 | + self.out = new_fvec(1) | |
| 82 | + aubio_peakpicker_set_threshold (self.pp, threshold) | |
| 83 | + def do(self,fv): | |
| 84 | + aubio_peakpicker_do(self.pp, fv(), self.out) | |
| 85 | + return fvec_read_sample(self.out, 0) | |
| 86 | + def getval(self): | |
| 87 | + return aubio_peakpicker_get_adaptive_threshold(self.pp) | |
| 88 | + def __del__(self): | |
| 89 | + del_aubio_peakpicker(self.pp) | |
| 90 | + | |
| 91 | +class onsetpick: | |
| 92 | + """ superclass for aubio_pvoc + aubio_specdesc + aubio_peakpicker """ | |
| 93 | + def __init__(self,bufsize,hopsize,myvec,threshold,mode='dual',derivate=False,dcthreshold=0): | |
| 94 | + self.myfft = cvec(bufsize) | |
| 95 | + self.pv = pvoc(bufsize,hopsize) | |
| 96 | + if mode in ['dual'] : | |
| 97 | + self.myod = onsetdetection("hfc",bufsize) | |
| 98 | + self.myod2 = onsetdetection("mkl",bufsize) | |
| 99 | + self.myonset = fvec(1) | |
| 100 | + self.myonset2 = fvec(1) | |
| 101 | + else: | |
| 102 | + self.myod = onsetdetection(mode,bufsize) | |
| 103 | + self.myonset = fvec(1) | |
| 104 | + self.mode = mode | |
| 105 | + self.pp = peakpick(float(threshold)) | |
| 106 | + self.derivate = derivate | |
| 107 | + self.dcthreshold = dcthreshold | |
| 108 | + self.oldval = 0. | |
| 109 | + | |
| 110 | + def do(self,myvec): | |
| 111 | + self.pv.do(myvec,self.myfft) | |
| 112 | + self.myod.do(self.myfft,self.myonset) | |
| 113 | + if self.mode == 'dual': | |
| 114 | + self.myod2.do(self.myfft,self.myonset2) | |
| 115 | + self.myonset.set(self.myonset.get(0)*self.myonset2.get(0),0) | |
| 116 | + if self.derivate: | |
| 117 | + val = self.myonset.get(0) | |
| 118 | + dval = val - self.oldval | |
| 119 | + self.oldval = val | |
| 120 | + if dval > 0: self.myonset.set(dval,0) | |
| 121 | + else: self.myonset.set(0.,0,0) | |
| 122 | + isonset, dval = self.pp.do(self.myonset),self.myonset.get(0) | |
| 123 | + if self.dcthreshold: | |
| 124 | + if dval < self.dcthreshold: isonset = 0 | |
| 125 | + return isonset, dval | |
| 126 | + | |
| 127 | +class pitch: | |
| 128 | + def __init__(self,mode="mcomb",bufsize=2048,hopsize=1024, | |
| 129 | + samplerate=44100.,omode="freq",tolerance=0.1): | |
| 130 | + self.pitchp = new_aubio_pitch(mode,bufsize,hopsize, | |
| 131 | + samplerate) | |
| 132 | + self.mypitch = fvec(1) | |
| 133 | + aubio_pitch_set_unit(self.pitchp,omode) | |
| 134 | + aubio_pitch_set_tolerance(self.pitchp,tolerance) | |
| 135 | + #self.filt = filter(srate,"adsgn") | |
| 136 | + def __del__(self): | |
| 137 | + del_aubio_pitch(self.pitchp) | |
| 138 | + def __call__(self,myvec): | |
| 139 | + aubio_pitch_do(self.pitchp,myvec(), self.mypitch()) | |
| 140 | + return self.mypitch.get(0) | |
| 141 | + | |
| 142 | +class filter: | |
| 143 | + def __init__(self,srate,type=None): | |
| 144 | + if (type=="adsgn"): | |
| 145 | + self.filter = new_aubio_adsgn_filter(srate) | |
| 146 | + def __del__(self): | |
| 147 | + #del_aubio_filter(self.filter) | |
| 148 | + pass | |
| 149 | + def __call__(self,myvec): | |
| 150 | + aubio_filter_do(self.filter,myvec()) | |
| 151 | + | |
| 152 | +class beattracking: | |
| 153 | + """ class for aubio_beattracking """ | |
| 154 | + def __init__(self,winlen,channels): | |
| 155 | + self.p = new_aubio_beattracking(winlen,channels) | |
| 156 | + def do(self,dfframe,out): | |
| 157 | + return aubio_beattracking_do(self.p,dfframe(),out()) | |
| 158 | + def __del__(self): | |
| 159 | + del_aubio_beattracking(self.p) | |
| 160 | + | |
Empty file added.
| @@ -0,0 +1,25 @@ | ||
| 1 | +from config import * | |
| 2 | + | |
| 3 | +class run_broadcast: | |
| 4 | + def __init__(self,command,*args): | |
| 5 | + for host in REMOTEHOSTS: | |
| 6 | + command(host,args[0],args[1:]) | |
| 7 | + | |
| 8 | +def remote_sync(host,path='',options=''): | |
| 9 | + optstring = '' | |
| 10 | + for i in options: | |
| 11 | + optstring = "%s %s" % (optstring,i) | |
| 12 | + print RSYNC_CMD,optstring,RSYNC_OPT,' --delete', | |
| 13 | + print '%s%s%s%s%s' % (path,'/ ',host,':',path) | |
| 14 | + | |
| 15 | + | |
| 16 | +def fetch_results(host,path='',options=''): | |
| 17 | + optstring = '' | |
| 18 | + for i in options: | |
| 19 | + optstring = "%s %s" % (optstring,i) | |
| 20 | + print RSYNC_CMD,optstring,RSYNC_OPT,' --update', | |
| 21 | + print '%s%s%s%s%s' % (host,':',path,'/ ',path) | |
| 22 | + | |
| 23 | +def remote_queue(host,command,options=''): | |
| 24 | + print 'oarsub -p "hostname = \'',host,'\'',command | |
| 25 | + | |
| @@ -0,0 +1,22 @@ | ||
| 1 | + | |
| 2 | +filefound = 0 | |
| 3 | +try: | |
| 4 | + filename = "/etc/aubio-bench.conf" | |
| 5 | + execfile(filename) | |
| 6 | + filefound = 1 | |
| 7 | +except IOError: | |
| 8 | + print "no system wide configuration file found in", filename | |
| 9 | + | |
| 10 | +try: | |
| 11 | + import os | |
| 12 | + filename = "%s%s%s" % (os.getenv('HOME'),os.sep,".aubio-bench.conf") | |
| 13 | + execfile(filename) | |
| 14 | + filefound = 1 | |
| 15 | +except IOError: | |
| 16 | + #print "no user configuration file found in", filename | |
| 17 | + pass | |
| 18 | + | |
| 19 | +if filefound == 0: | |
| 20 | + import sys | |
| 21 | + print "error: no configuration file found at all" | |
| 22 | + sys.exit(1) | |
| @@ -0,0 +1,224 @@ | ||
| 1 | +from config import * | |
| 2 | +import commands,sys | |
| 3 | +import re | |
| 4 | + | |
| 5 | +def runcommand(cmd,debug=0): | |
| 6 | + if VERBOSE >= VERBOSE_CMD or debug: print cmd | |
| 7 | + if debug: return | |
| 8 | + status, output = commands.getstatusoutput(cmd) | |
| 9 | + if status == 0 or VERBOSE >= VERBOSE_OUT: | |
| 10 | + output = output.split('\n') | |
| 11 | + if VERBOSE >= VERBOSE_OUT: | |
| 12 | + for i in output: | |
| 13 | + if i: print i | |
| 14 | + if not status == 0: | |
| 15 | + print 'error:',status,output | |
| 16 | + print 'command returning error was',cmd | |
| 17 | + #sys.exit(1) | |
| 18 | + if output == '' or output == ['']: return | |
| 19 | + return output | |
| 20 | + | |
| 21 | +def list_files(datapath,filter='f', maxdepth = -1): | |
| 22 | + if not os.path.exists(datapath): | |
| 23 | ||
| 24 | + print "ERR: no directory %s were found" % datapath | |
| 25 | + sys.exit(1) | |
| 26 | + if maxdepth >= 0: maxstring = " -maxdepth %d " % maxdepth | |
| 27 | + else: maxstring = "" | |
| 28 | + cmd = '%s' * 6 % ('find ',datapath,maxstring,' -type ',filter, "| sort -n") | |
| 29 | + return runcommand(cmd) | |
| 30 | + | |
| 31 | +def list_wav_files(datapath,maxdepth = -1): | |
| 32 | + return list_files(datapath, filter="f -name '*.wav'",maxdepth = maxdepth) | |
| 33 | + | |
| 34 | +sndfile_filter = "f -name '*.wav' -o -name '*.aif' -o -name '*.aiff'" | |
| 35 | + | |
| 36 | +def list_snd_files(datapath,maxdepth = -1): | |
| 37 | + return list_files(datapath, filter=sndfile_filter, | |
| 38 | + maxdepth = maxdepth) | |
| 39 | + | |
| 40 | +def list_res_files(datapath,maxdepth = -1): | |
| 41 | + return list_files(datapath, filter="f -name '*.txt'", maxdepth = maxdepth) | |
| 42 | + | |
| 43 | +def list_dirs(datapath): | |
| 44 | + return list_files(datapath, filter="d") | |
| 45 | + | |
| 46 | +def mkdir(path): | |
| 47 | + cmd = '%s%s' % ('mkdir -p ',path) | |
| 48 | + return runcommand(cmd) | |
| 49 | + | |
| 50 | +def act_on_data (action,datapath,respath=None,suffix='.txt',filter='f',sub='\.wav$',**keywords): | |
| 51 | + """ execute action(datafile,resfile) on all files in datapath """ | |
| 52 | + dirlist = list_files(datapath,filter=filter) | |
| 53 | + if dirlist == ['']: dirlist = [] | |
| 54 | + if respath: | |
| 55 | + respath_in_datapath = re.split(datapath, respath,maxsplit=1)[1:] | |
| 56 | + if(respath_in_datapath and suffix == ''): | |
| 57 | + print 'error: respath in datapath and no suffix used' | |
| 58 | + for i in dirlist: | |
| 59 | + j = re.split(datapath, i,maxsplit=1)[1] | |
| 60 | + j = re.sub(sub,'',j) | |
| 61 | + #j = "%s%s%s"%(respath,j,suffix) | |
| 62 | + if respath: | |
| 63 | + j = "%s%s"%(respath,j) | |
| 64 | + if sub != '': | |
| 65 | + j = re.sub(sub,suffix,j) | |
| 66 | + else: | |
| 67 | + j = "%s%s" % (j,suffix) | |
| 68 | + action(i,j,**keywords) | |
| 69 | + | |
| 70 | +def act_on_results (action,datapath,respath,filter='d'): | |
| 71 | + """ execute action(respath) an all subdirectories in respath """ | |
| 72 | + dirlist = list_files(datapath,filter='d') | |
| 73 | + respath_in_datapath = re.split(datapath, respath,maxsplit=1)[1:] | |
| 74 | + if(respath_in_datapath and not filter == 'd' and suffix == ''): | |
| 75 | + print 'warning: respath is in datapath' | |
| 76 | + for i in dirlist: | |
| 77 | + s = re.split(datapath, i ,maxsplit=1)[1] | |
| 78 | + action("%s%s%s"%(respath,'/',s)) | |
| 79 | + | |
| 80 | +def act_on_files (action,listfiles,listres=None,suffix='.txt',filter='f',sub='\.wav$',**keywords): | |
| 81 | + """ execute action(respath) an all subdirectories in respath """ | |
| 82 | + if listres and len(listfiles) <= len(listres): | |
| 83 | + for i in range(len(listfiles)): | |
| 84 | + action(listfiles[i],listres[i],**keywords) | |
| 85 | + else: | |
| 86 | + for i in listfiles: | |
| 87 | + action(i,None,**keywords) | |
| 88 | + | |
| 89 | +class bench: | |
| 90 | + """ class to run benchmarks on directories """ | |
| 91 | + def __init__(self,datadir,resdir=None,checkres=False,checkanno=False,params=[]): | |
| 92 | + from aubio.task.params import taskparams | |
| 93 | + self.datadir = datadir | |
| 94 | + # path to write results path to | |
| 95 | + self.resdir = resdir | |
| 96 | + # list of annotation files | |
| 97 | + self.reslist = [] | |
| 98 | + # list used to gather results | |
| 99 | + self.results = [] | |
| 100 | + if not params: self.params = taskparams() | |
| 101 | + else: self.params = params | |
| 102 | + print "Checking data directory", self.datadir | |
| 103 | + self.checkdata() | |
| 104 | + if checkanno: self.checkanno() | |
| 105 | + if checkres: self.checkres() | |
| 106 | + | |
| 107 | + def checkdata(self): | |
| 108 | + if os.path.isfile(self.datadir): | |
| 109 | + self.dirlist = os.path.dirname(self.datadir) | |
| 110 | + elif os.path.isdir(self.datadir): | |
| 111 | + self.dirlist = list_dirs(self.datadir) | |
| 112 | + # allow dir* matching through find commands? | |
| 113 | + else: | |
| 114 | + print "ERR: path not understood" | |
| 115 | + sys.exit(1) | |
| 116 | + print "Listing directories in data directory", | |
| 117 | + if self.dirlist: | |
| 118 | + print " (%d elements)" % len(self.dirlist) | |
| 119 | + else: | |
| 120 | + print " (0 elements)" | |
| 121 | + print "ERR: no directory %s were found" % self.datadir | |
| 122 | + sys.exit(1) | |
| 123 | + print "Listing sound files in data directory", | |
| 124 | + self.sndlist = list_snd_files(self.datadir) | |
| 125 | + if self.sndlist: | |
| 126 | + print " (%d elements)" % len(self.sndlist) | |
| 127 | + else: | |
| 128 | + print " (0 elements)" | |
| 129 | + print "ERR: no sound files were found in", self.datadir | |
| 130 | + sys.exit(1) | |
| 131 | + | |
| 132 | + def checkanno(self): | |
| 133 | + print "Listing annotations in data directory", | |
| 134 | + self.reslist = list_res_files(self.datadir) | |
| 135 | + print " (%d elements)" % len(self.reslist) | |
| 136 | + #for each in self.reslist: print each | |
| 137 | + if not self.reslist or len(self.reslist) < len (self.sndlist): | |
| 138 | + print "ERR: not enough annotations" | |
| 139 | + return -1 | |
| 140 | + else: | |
| 141 | + print "Found enough annotations" | |
| 142 | + | |
| 143 | + def checkres(self): | |
| 144 | + print "Creating results directory" | |
| 145 | + act_on_results(mkdir,self.datadir,self.resdir,filter='d') | |
| 146 | + | |
| 147 | + def pretty_print(self,sep='|'): | |
| 148 | + for i in self.printnames: | |
| 149 | + print self.formats[i] % self.v[i], sep, | |
| 150 | ||
| 151 | + | |
| 152 | + def pretty_titles(self,sep='|'): | |
| 153 | + for i in self.printnames: | |
| 154 | + print self.formats[i] % i, sep, | |
| 155 | ||
| 156 | + | |
| 157 | + def dir_exec(self): | |
| 158 | + """ run file_exec on every input file """ | |
| 159 | + self.l , self.labs = [], [] | |
| 160 | + self.v = {} | |
| 161 | + for i in self.valuenames: | |
| 162 | + self.v[i] = [] | |
| 163 | + for i in self.valuelists: | |
| 164 | + self.v[i] = [] | |
| 165 | + act_on_files(self.file_exec,self.sndlist,self.reslist, \ | |
| 166 | + suffix='',filter=sndfile_filter) | |
| 167 | + | |
| 168 | + def dir_eval(self): | |
| 169 | + pass | |
| 170 | + | |
| 171 | + def file_gettruth(self,input): | |
| 172 | + """ get ground truth filenames """ | |
| 173 | + from os.path import isfile | |
| 174 | + ftrulist = [] | |
| 175 | + # search for match as filetask.input,".txt" | |
| 176 | + ftru = '.'.join(input.split('.')[:-1]) | |
| 177 | + ftru = '.'.join((ftru,'txt')) | |
| 178 | + if isfile(ftru): | |
| 179 | + ftrulist.append(ftru) | |
| 180 | + else: | |
| 181 | + # search for matches for filetask.input in the list of results | |
| 182 | + for i in range(len(self.reslist)): | |
| 183 | + check = '.'.join(self.reslist[i].split('.')[:-1]) | |
| 184 | + check = '_'.join(check.split('_')[:-1]) | |
| 185 | + if check == '.'.join(input.split('.')[:-1]): | |
| 186 | + ftrulist.append(self.reslist[i]) | |
| 187 | + return ftrulist | |
| 188 | + | |
| 189 | + def file_exec(self,input,output): | |
| 190 | + """ create filetask, extract data, evaluate """ | |
| 191 | + filetask = self.task(input,params=self.params) | |
| 192 | + computed_data = filetask.compute_all() | |
| 193 | + ftrulist = self.file_gettruth(filetask.input) | |
| 194 | + for i in ftrulist: | |
| 195 | + filetask.eval(computed_data,i,mode='rocloc',vmode='') | |
| 196 | + """ append filetask.v to self.v """ | |
| 197 | + for i in self.valuenames: | |
| 198 | + self.v[i].append(filetask.v[i]) | |
| 199 | + for j in self.valuelists: | |
| 200 | + if filetask.v[j]: | |
| 201 | + for i in range(len(filetask.v[j])): | |
| 202 | + self.v[j].append(filetask.v[j][i]) | |
| 203 | + | |
| 204 | + def file_eval(self): | |
| 205 | + pass | |
| 206 | + | |
| 207 | + def file_plot(self): | |
| 208 | + pass | |
| 209 | + | |
| 210 | + def dir_plot(self): | |
| 211 | + pass | |
| 212 | + | |
| 213 | + def run_bench(self): | |
| 214 | + for mode in self.modes: | |
| 215 | + self.params.mode = mode | |
| 216 | + self.dir_exec() | |
| 217 | + self.dir_eval() | |
| 218 | + self.dir_plot() | |
| 219 | + | |
| 220 | + def dir_eval_print(self): | |
| 221 | + self.dir_exec() | |
| 222 | + self.dir_eval() | |
| 223 | + self.pretty_print() | |
| 224 | + | |
| @@ -0,0 +1,303 @@ | ||
| 1 | + | |
| 2 | +from aubio.bench.node import * | |
| 3 | +from os.path import dirname,basename | |
| 4 | + | |
| 5 | +def mmean(l): | |
| 6 | + return sum(l)/max(float(len(l)),1) | |
| 7 | + | |
| 8 | +def stdev(l): | |
| 9 | + smean = 0 | |
| 10 | + if not len(l): return smean | |
| 11 | + lmean = mmean(l) | |
| 12 | + for i in l: | |
| 13 | + smean += (i-lmean)**2 | |
| 14 | + smean *= 1. / len(l) | |
| 15 | + return smean**.5 | |
| 16 | + | |
| 17 | +class benchonset(bench): | |
| 18 | + | |
| 19 | + """ list of values to store per file """ | |
| 20 | + valuenames = ['orig','missed','Tm','expc','bad','Td'] | |
| 21 | + """ list of lists to store per file """ | |
| 22 | + valuelists = ['l','labs'] | |
| 23 | + """ list of values to print per dir """ | |
| 24 | + printnames = [ 'mode', 'thres', 'dist', 'prec', 'recl', | |
| 25 | + 'GD', 'FP', | |
| 26 | + 'Torig', 'Ttrue', 'Tfp', 'Tfn', 'TTm', 'TTd', | |
| 27 | + 'aTtrue', 'aTfp', 'aTfn', 'aTm', 'aTd', | |
| 28 | + 'mean', 'smean', 'amean', 'samean'] | |
| 29 | + | |
| 30 | + """ per dir """ | |
| 31 | + formats = {'mode': "%12s" , 'thres': "%5.4s", | |
| 32 | + 'dist': "%5.4s", 'prec': "%5.4s", 'recl': "%5.4s", | |
| 33 | + 'Torig': "%5.4s", 'Ttrue': "%5.4s", 'Tfp': "%5.4s", 'Tfn': "%5.4s", | |
| 34 | + 'TTm': "%5.4s", 'TTd': "%5.4s", | |
| 35 | + 'aTtrue':"%5.4s", 'aTfp': "%5.4s", 'aTfn': "%5.4s", | |
| 36 | + 'aTm': "%5.4s", 'aTd': "%5.4s", | |
| 37 | + 'mean': "%5.6s", 'smean': "%5.6s", | |
| 38 | + 'amean': "%5.6s", 'samean': "%5.6s", | |
| 39 | + "GD": "%5.4s", "FP": "%5.4s", | |
| 40 | + "GDm": "%5.4s", "FPd": "%5.4s", | |
| 41 | + "bufsize": "%5.4s", "hopsize": "%5.4s", | |
| 42 | + "time": "%5.4s"} | |
| 43 | + | |
| 44 | + def dir_eval(self): | |
| 45 | + """ evaluate statistical data over the directory """ | |
| 46 | + v = self.v | |
| 47 | + | |
| 48 | + v['mode'] = self.params.onsetmode | |
| 49 | + v['thres'] = self.params.threshold | |
| 50 | + v['bufsize'] = self.params.bufsize | |
| 51 | + v['hopsize'] = self.params.hopsize | |
| 52 | + v['silence'] = self.params.silence | |
| 53 | + v['mintol'] = self.params.mintol | |
| 54 | + | |
| 55 | + v['Torig'] = sum(v['orig']) | |
| 56 | + v['TTm'] = sum(v['Tm']) | |
| 57 | + v['TTd'] = sum(v['Td']) | |
| 58 | + v['Texpc'] = sum(v['expc']) | |
| 59 | + v['Tbad'] = sum(v['bad']) | |
| 60 | + v['Tmissed'] = sum(v['missed']) | |
| 61 | + v['aTm'] = mmean(v['Tm']) | |
| 62 | + v['aTd'] = mmean(v['Td']) | |
| 63 | + | |
| 64 | + v['mean'] = mmean(v['l']) | |
| 65 | + v['smean'] = stdev(v['l']) | |
| 66 | + | |
| 67 | + v['amean'] = mmean(v['labs']) | |
| 68 | + v['samean'] = stdev(v['labs']) | |
| 69 | + | |
| 70 | + # old type calculations | |
| 71 | + # good detection rate | |
| 72 | + v['GD'] = 100.*(v['Torig']-v['Tmissed']-v['TTm'])/v['Torig'] | |
| 73 | + # false positive rate | |
| 74 | + v['FP'] = 100.*(v['Tbad']+v['TTd'])/v['Torig'] | |
| 75 | + # good detection counting merged detections as good | |
| 76 | + v['GDm'] = 100.*(v['Torig']-v['Tmissed'])/v['Torig'] | |
| 77 | + # false positives counting doubled as good | |
| 78 | + v['FPd'] = 100.*v['Tbad']/v['Torig'] | |
| 79 | + | |
| 80 | + # mirex type annotations | |
| 81 | + totaltrue = v['Texpc']-v['Tbad']-v['TTd'] | |
| 82 | + totalfp = v['Tbad']+v['TTd'] | |
| 83 | + totalfn = v['Tmissed']+v['TTm'] | |
| 84 | + self.v['Ttrue'] = totaltrue | |
| 85 | + self.v['Tfp'] = totalfp | |
| 86 | + self.v['Tfn'] = totalfn | |
| 87 | + # average over the number of annotation files | |
| 88 | + N = float(len(self.reslist)) | |
| 89 | + self.v['aTtrue'] = totaltrue/N | |
| 90 | + self.v['aTfp'] = totalfp/N | |
| 91 | + self.v['aTfn'] = totalfn/N | |
| 92 | + | |
| 93 | + # F-measure | |
| 94 | + self.P = 100.*float(totaltrue)/max(totaltrue + totalfp,1) | |
| 95 | + self.R = 100.*float(totaltrue)/max(totaltrue + totalfn,1) | |
| 96 | + #if self.R < 0: self.R = 0 | |
| 97 | + self.F = 2.* self.P*self.R / max(float(self.P+self.R),1) | |
| 98 | + self.v['dist'] = self.F | |
| 99 | + self.v['prec'] = self.P | |
| 100 | + self.v['recl'] = self.R | |
| 101 | + | |
| 102 | + | |
| 103 | + """ | |
| 104 | + Plot functions | |
| 105 | + """ | |
| 106 | + | |
| 107 | + def plotroc(self,d,plottitle=""): | |
| 108 | + import Gnuplot, Gnuplot.funcutils | |
| 109 | + gd = [] | |
| 110 | + fp = [] | |
| 111 | + for i in self.vlist: | |
| 112 | + gd.append(i['GD']) | |
| 113 | + fp.append(i['FP']) | |
| 114 | + d.append(Gnuplot.Data(fp, gd, with_='linespoints', | |
| 115 | + title="%s %s" % (plottitle,i['mode']) )) | |
| 116 | + | |
| 117 | + def plotplotroc(self,d,outplot=0,extension='ps'): | |
| 118 | + import Gnuplot, Gnuplot.funcutils | |
| 119 | + from sys import exit | |
| 120 | + g = Gnuplot.Gnuplot(debug=0, persist=1) | |
| 121 | + if outplot: | |
| 122 | + if extension == 'ps': ext, extension = '.ps' , 'postscript' | |
| 123 | + elif extension == 'png': ext, extension = '.png', 'png' | |
| 124 | + elif extension == 'svg': ext, extension = '.svg', 'svg' | |
| 125 | + else: exit("ERR: unknown plot extension") | |
| 126 | + g('set terminal %s' % extension) | |
| 127 | + g('set output \'roc-%s%s\'' % (outplot,ext)) | |
| 128 | + xmax = 30 #max(fp) | |
| 129 | + ymin = 50 | |
| 130 | + g('set xrange [0:%f]' % xmax) | |
| 131 | + g('set yrange [%f:100]' % ymin) | |
| 132 | + # grid set | |
| 133 | + g('set grid') | |
| 134 | + g('set xtics 0,5,%f' % xmax) | |
| 135 | + g('set ytics %f,5,100' % ymin) | |
| 136 | + g('set key 27,65') | |
| 137 | + #g('set format \"%g\"') | |
| 138 | + g.title(basename(self.datadir)) | |
| 139 | + g.xlabel('false positives (%)') | |
| 140 | + g.ylabel('correct detections (%)') | |
| 141 | + g.plot(*d) | |
| 142 | + | |
| 143 | + def plotpr(self,d,plottitle=""): | |
| 144 | + import Gnuplot, Gnuplot.funcutils | |
| 145 | + x = [] | |
| 146 | + y = [] | |
| 147 | + for i in self.vlist: | |
| 148 | + x.append(i['prec']) | |
| 149 | + y.append(i['recl']) | |
| 150 | + d.append(Gnuplot.Data(x, y, with_='linespoints', | |
| 151 | + title="%s %s" % (plottitle,i['mode']) )) | |
| 152 | + | |
| 153 | + def plotplotpr(self,d,outplot=0,extension='ps'): | |
| 154 | + import Gnuplot, Gnuplot.funcutils | |
| 155 | + from sys import exit | |
| 156 | + g = Gnuplot.Gnuplot(debug=0, persist=1) | |
| 157 | + if outplot: | |
| 158 | + if extension == 'ps': ext, extension = '.ps' , 'postscript' | |
| 159 | + elif extension == 'png': ext, extension = '.png', 'png' | |
| 160 | + elif extension == 'svg': ext, extension = '.svg', 'svg' | |
| 161 | + else: exit("ERR: unknown plot extension") | |
| 162 | + g('set terminal %s' % extension) | |
| 163 | + g('set output \'pr-%s%s\'' % (outplot,ext)) | |
| 164 | + g.title(basename(self.datadir)) | |
| 165 | + g.xlabel('Recall (%)') | |
| 166 | + g.ylabel('Precision (%)') | |
| 167 | + g.plot(*d) | |
| 168 | + | |
| 169 | + def plotfmeas(self,d,plottitle=""): | |
| 170 | + import Gnuplot, Gnuplot.funcutils | |
| 171 | + x,y = [],[] | |
| 172 | + for i in self.vlist: | |
| 173 | + x.append(i['thres']) | |
| 174 | + y.append(i['dist']) | |
| 175 | + d.append(Gnuplot.Data(x, y, with_='linespoints', | |
| 176 | + title="%s %s" % (plottitle,i['mode']) )) | |
| 177 | + | |
| 178 | + def plotplotfmeas(self,d,outplot="",extension='ps', title="F-measure"): | |
| 179 | + import Gnuplot, Gnuplot.funcutils | |
| 180 | + from sys import exit | |
| 181 | + g = Gnuplot.Gnuplot(debug=0, persist=1) | |
| 182 | + if outplot: | |
| 183 | + if extension == 'ps': terminal = 'postscript' | |
| 184 | + elif extension == 'png': terminal = 'png' | |
| 185 | + elif extension == 'svg': terminal = 'svg' | |
| 186 | + else: exit("ERR: unknown plot extension") | |
| 187 | + g('set terminal %s' % terminal) | |
| 188 | + g('set output \'fmeas-%s.%s\'' % (outplot,extension)) | |
| 189 | + g.xlabel('threshold \\delta') | |
| 190 | + g.ylabel('F-measure (%)') | |
| 191 | + g('set xrange [0:1.2]') | |
| 192 | + g('set yrange [0:100]') | |
| 193 | + g.title(basename(self.datadir)) | |
| 194 | + # grid set | |
| 195 | + #g('set grid') | |
| 196 | + #g('set xtics 0,5,%f' % xmax) | |
| 197 | + #g('set ytics %f,5,100' % ymin) | |
| 198 | + #g('set key 27,65') | |
| 199 | + #g('set format \"%g\"') | |
| 200 | + g.plot(*d) | |
| 201 | + | |
| 202 | + def plotfmeasvar(self,d,var,plottitle=""): | |
| 203 | + import Gnuplot, Gnuplot.funcutils | |
| 204 | + x,y = [],[] | |
| 205 | + for i in self.vlist: | |
| 206 | + x.append(i[var]) | |
| 207 | + y.append(i['dist']) | |
| 208 | + d.append(Gnuplot.Data(x, y, with_='linespoints', | |
| 209 | + title="%s %s" % (plottitle,i['mode']) )) | |
| 210 | + | |
| 211 | + def plotplotfmeasvar(self,d,var,outplot="",extension='ps', title="F-measure"): | |
| 212 | + import Gnuplot, Gnuplot.funcutils | |
| 213 | + from sys import exit | |
| 214 | + g = Gnuplot.Gnuplot(debug=0, persist=1) | |
| 215 | + if outplot: | |
| 216 | + if extension == 'ps': terminal = 'postscript' | |
| 217 | + elif extension == 'png': terminal = 'png' | |
| 218 | + elif extension == 'svg': terminal = 'svg' | |
| 219 | + else: exit("ERR: unknown plot extension") | |
| 220 | + g('set terminal %s' % terminal) | |
| 221 | + g('set output \'fmeas-%s.%s\'' % (outplot,extension)) | |
| 222 | + g.xlabel(var) | |
| 223 | + g.ylabel('F-measure (%)') | |
| 224 | + #g('set xrange [0:1.2]') | |
| 225 | + g('set yrange [0:100]') | |
| 226 | + g.title(basename(self.datadir)) | |
| 227 | + g.plot(*d) | |
| 228 | + | |
| 229 | + def plotdiffs(self,d,plottitle=""): | |
| 230 | + import Gnuplot, Gnuplot.funcutils | |
| 231 | + v = self.v | |
| 232 | + l = v['l'] | |
| 233 | + mean = v['mean'] | |
| 234 | + smean = v['smean'] | |
| 235 | + amean = v['amean'] | |
| 236 | + samean = v['samean'] | |
| 237 | + val = [] | |
| 238 | + per = [0] * 100 | |
| 239 | + for i in range(0,100): | |
| 240 | + val.append(i*.001-.05) | |
| 241 | + for j in l: | |
| 242 | + if abs(j-val[i]) <= 0.001: | |
| 243 | + per[i] += 1 | |
| 244 | + total = v['Torig'] | |
| 245 | + for i in range(len(per)): per[i] /= total/100. | |
| 246 | + | |
| 247 | + d.append(Gnuplot.Data(val, per, with_='fsteps', | |
| 248 | + title="%s %s" % (plottitle,v['mode']) )) | |
| 249 | + #d.append('mean=%f,sigma=%f,eps(x) title \"\"'% (mean,smean)) | |
| 250 | + #d.append('mean=%f,sigma=%f,eps(x) title \"\"'% (amean,samean)) | |
| 251 | + | |
| 252 | + | |
| 253 | + def plotplotdiffs(self,d,outplot=0,extension='ps'): | |
| 254 | + import Gnuplot, Gnuplot.funcutils | |
| 255 | + from sys import exit | |
| 256 | + g = Gnuplot.Gnuplot(debug=0, persist=1) | |
| 257 | + if outplot: | |
| 258 | + if extension == 'ps': ext, extension = '.ps' , 'postscript' | |
| 259 | + elif extension == 'png': ext, extension = '.png', 'png' | |
| 260 | + elif extension == 'svg': ext, extension = '.svg', 'svg' | |
| 261 | + else: exit("ERR: unknown plot extension") | |
| 262 | + g('set terminal %s' % extension) | |
| 263 | + g('set output \'diffhist-%s%s\'' % (outplot,ext)) | |
| 264 | + g('eps(x) = 1./(sigma*(2.*3.14159)**.5) * exp ( - ( x - mean ) ** 2. / ( 2. * sigma ** 2. ))') | |
| 265 | + g.title(basename(self.datadir)) | |
| 266 | + g.xlabel('delay to hand-labelled onset (s)') | |
| 267 | + g.ylabel('% number of correct detections / ms ') | |
| 268 | + g('set xrange [-0.05:0.05]') | |
| 269 | + g('set yrange [0:20]') | |
| 270 | + g.plot(*d) | |
| 271 | + | |
| 272 | + | |
| 273 | + def plothistcat(self,d,plottitle=""): | |
| 274 | + import Gnuplot, Gnuplot.funcutils | |
| 275 | + total = v['Torig'] | |
| 276 | + for i in range(len(per)): per[i] /= total/100. | |
| 277 | + | |
| 278 | + d.append(Gnuplot.Data(val, per, with_='fsteps', | |
| 279 | + title="%s %s" % (plottitle,v['mode']) )) | |
| 280 | + #d.append('mean=%f,sigma=%f,eps(x) title \"\"'% (mean,smean)) | |
| 281 | + #d.append('mean=%f,sigma=%f,eps(x) title \"\"'% (amean,samean)) | |
| 282 | + | |
| 283 | + | |
| 284 | + def plotplothistcat(self,d,outplot=0,extension='ps'): | |
| 285 | + import Gnuplot, Gnuplot.funcutils | |
| 286 | + from sys import exit | |
| 287 | + g = Gnuplot.Gnuplot(debug=0, persist=1) | |
| 288 | + if outplot: | |
| 289 | + if extension == 'ps': ext, extension = '.ps' , 'postscript' | |
| 290 | + elif extension == 'png': ext, extension = '.png', 'png' | |
| 291 | + elif extension == 'svg': ext, extension = '.svg', 'svg' | |
| 292 | + else: exit("ERR: unknown plot extension") | |
| 293 | + g('set terminal %s' % extension) | |
| 294 | + g('set output \'diffhist-%s%s\'' % (outplot,ext)) | |
| 295 | + g('eps(x) = 1./(sigma*(2.*3.14159)**.5) * exp ( - ( x - mean ) ** 2. / ( 2. * sigma ** 2. ))') | |
| 296 | + g.title(basename(self.datadir)) | |
| 297 | + g.xlabel('delay to hand-labelled onset (s)') | |
| 298 | + g.ylabel('% number of correct detections / ms ') | |
| 299 | + g('set xrange [-0.05:0.05]') | |
| 300 | + g('set yrange [0:20]') | |
| 301 | + g.plot(*d) | |
| 302 | + | |
| 303 | + | |
| @@ -0,0 +1,222 @@ | ||
| 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-2009 Paul Brossier <piem@aubio.org> | |
| 7 | + | |
| 8 | + This file is part of aubio. | |
| 9 | + | |
| 10 | + aubio is free software: you can redistribute it and/or modify | |
| 11 | + it under the terms of the GNU General Public License as published by | |
| 12 | + the Free Software Foundation, either version 3 of the License, or | |
| 13 | + (at your option) any later version. | |
| 14 | + | |
| 15 | + aubio is distributed in the hope that it will be useful, | |
| 16 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 17 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 18 | + GNU General Public License for more details. | |
| 19 | + | |
| 20 | + You should have received a copy of the GNU General Public License | |
| 21 | + along with aubio. If not, see <http://www.gnu.org/licenses/>. | |
| 22 | +""" | |
| 23 | + | |
| 24 | + | |
| 25 | +def audio_to_array(filename): | |
| 26 | + import aubio.aubioclass | |
| 27 | + from numpy import arange | |
| 28 | + hopsize = 2048 | |
| 29 | + filei = aubio.aubioclass.sndfile(filename) | |
| 30 | + framestep = 1/(filei.samplerate()+0.) | |
| 31 | + channels = filei.channels() | |
| 32 | + myvec = aubio.aubioclass.fvec(hopsize,channels) | |
| 33 | + data = [] | |
| 34 | + readsize = hopsize | |
| 35 | + while (readsize==hopsize): | |
| 36 | + readsize = filei.read(hopsize,myvec) | |
| 37 | + #for i in range(channels): | |
| 38 | + i = 0 | |
| 39 | + curpos = 0 | |
| 40 | + while (curpos < readsize): | |
| 41 | + data.append(myvec.get(curpos,i)) | |
| 42 | + curpos+=1 | |
| 43 | + time = arange(len(data))*framestep | |
| 44 | + return time,data | |
| 45 | + | |
| 46 | +def plot_audio(filenames, g, options): | |
| 47 | + todraw = len(filenames) | |
| 48 | + xorig = 0. | |
| 49 | + xratio = 1./todraw | |
| 50 | + g('set multiplot;') | |
| 51 | + while (len(filenames)): | |
| 52 | + time,data = audio_to_array(filenames.pop(0)) | |
| 53 | + if todraw==1: | |
| 54 | + if max(time) < 1.: | |
| 55 | + time = [t*1000. for t in time] | |
| 56 | + g.xlabel('Time (ms)') | |
| 57 | + else: | |
| 58 | + g.xlabel('Time (s)') | |
| 59 | + g.ylabel('Amplitude') | |
| 60 | + curplot = make_audio_plot(time,data) | |
| 61 | + g('set size %f,%f;' % (options.xsize*xratio,options.ysize) ) | |
| 62 | + g('set origin %f,0.;' % (xorig) ) | |
| 63 | + g('set style data lines; \ | |
| 64 | + set yrange [-1.:1.]; \ | |
| 65 | + set xrange [0:%f]' % time[-1]) | |
| 66 | + g.plot(curplot) | |
| 67 | + xorig += options.xsize*xratio | |
| 68 | + g('unset multiplot;') | |
| 69 | + | |
| 70 | +def audio_to_spec(filename,minf = 0, maxf = 0, lowthres = -20., | |
| 71 | + bufsize= 8192, hopsize = 1024): | |
| 72 | + from aubioclass import fvec,cvec,pvoc,sndfile | |
| 73 | + from math import log10 | |
| 74 | + filei = sndfile(filename) | |
| 75 | + srate = float(filei.samplerate()) | |
| 76 | + framestep = hopsize/srate | |
| 77 | + freqstep = srate/bufsize | |
| 78 | + channels = filei.channels() | |
| 79 | + myvec = fvec(hopsize,channels) | |
| 80 | + myfft = cvec(bufsize,channels) | |
| 81 | + pv = pvoc(bufsize,hopsize,channels) | |
| 82 | + data,time,freq = [],[],[] | |
| 83 | + | |
| 84 | + if maxf == 0.: maxf = bufsize/2 | |
| 85 | + else: maxf = int(maxf/freqstep) | |
| 86 | + if minf: minf = int(minf/freqstep) | |
| 87 | + else: minf = 0 | |
| 88 | + | |
| 89 | + for f in range(minf,maxf): | |
| 90 | + freq.append(f*freqstep) | |
| 91 | + readsize = hopsize | |
| 92 | + frameread = 0 | |
| 93 | + while (readsize==hopsize): | |
| 94 | + readsize = filei.read(hopsize,myvec) | |
| 95 | + pv.do(myvec,myfft) | |
| 96 | + frame = [] | |
| 97 | + i = 0 #for i in range(channels): | |
| 98 | + curpos = minf | |
| 99 | + while (curpos < maxf): | |
| 100 | + frame.append(max(lowthres,20.*log10(myfft.get(curpos,i)**2+0.00001))) | |
| 101 | + curpos+=1 | |
| 102 | + time.append(frameread*framestep) | |
| 103 | + data.append(frame) | |
| 104 | + frameread += 1 | |
| 105 | + # crop data if unfinished frames | |
| 106 | + if len(data[-1]) != len(data[0]): | |
| 107 | + data = data[0:-2] | |
| 108 | + time = time[0:-2] | |
| 109 | + # verify size consistency | |
| 110 | + assert len(data) == len(time) | |
| 111 | + assert len(data[0]) == len(freq) | |
| 112 | + return data,time,freq | |
| 113 | + | |
| 114 | +def plot_spec(filename, g, options): | |
| 115 | + import Gnuplot | |
| 116 | + data,time,freq = audio_to_spec(filename, | |
| 117 | + minf=options.minf,maxf=options.maxf, | |
| 118 | + bufsize=options.bufsize,hopsize=options.hopsize) | |
| 119 | + xorig = 0. | |
| 120 | + if max(time) < 1.: | |
| 121 | + time = [t*1000. for t in time] | |
| 122 | + g.xlabel('Time (ms)') | |
| 123 | + else: | |
| 124 | + g.xlabel('Time (s)') | |
| 125 | + if options.xsize < 0.5 and not options.log and max(time) > 1.: | |
| 126 | + freq = [f/1000. for f in freq] | |
| 127 | + options.minf /= 1000. | |
| 128 | + options.maxf /= 1000. | |
| 129 | + g.ylabel('Frequency (kHz)') | |
| 130 | + else: | |
| 131 | + g.ylabel('Frequency (Hz)') | |
| 132 | + g('set pm3d map') | |
| 133 | + g('set palette rgbformulae -25,-24,-32') | |
| 134 | + g('set cbtics 20') | |
| 135 | + #g('set colorbox horizontal') | |
| 136 | + g('set xrange [0.:%f]' % time[-1]) | |
| 137 | + if options.log: | |
| 138 | + g('set log y') | |
| 139 | + g('set yrange [%f:%f]' % (max(10,options.minf),options.maxf)) | |
| 140 | + else: | |
| 141 | + g('set yrange [%f:%f]' % (options.minf,options.maxf)) | |
| 142 | + g.splot(Gnuplot.GridData(data,time,freq, binary=1)) | |
| 143 | + #xorig += 1./todraw | |
| 144 | + | |
| 145 | +def downsample_audio(time,data,maxpoints=10000): | |
| 146 | + """ resample audio data to last only maxpoints """ | |
| 147 | + from numpy import array, resize | |
| 148 | + length = len(time) | |
| 149 | + downsample = length/maxpoints | |
| 150 | + if downsample == 0: downsample = 1 | |
| 151 | + x = resize(array(time),length)[0:-1:downsample] | |
| 152 | + y = resize(array(data),length)[0:-1:downsample] | |
| 153 | + return x,y | |
| 154 | + | |
| 155 | +def make_audio_plot(time,data,maxpoints=10000): | |
| 156 | + """ create gnuplot plot from an audio file """ | |
| 157 | + import Gnuplot, Gnuplot.funcutils | |
| 158 | + x,y = downsample_audio(time,data,maxpoints=maxpoints) | |
| 159 | + return Gnuplot.Data(x,y,with_='lines') | |
| 160 | + | |
| 161 | +def make_audio_envelope(time,data,maxpoints=10000): | |
| 162 | + """ create gnuplot plot from an audio file """ | |
| 163 | + from numpy import array | |
| 164 | + import Gnuplot, Gnuplot.funcutils | |
| 165 | + bufsize = 500 | |
| 166 | + x = [i.mean() for i in resize(array(time), (len(time)/bufsize,bufsize))] | |
| 167 | + y = [i.mean() for i in resize(array(data), (len(time)/bufsize,bufsize))] | |
| 168 | + x,y = downsample_audio(x,y,maxpoints=maxpoints) | |
| 169 | + return Gnuplot.Data(x,y,with_='lines') | |
| 170 | + | |
| 171 | +def gnuplot_addargs(parser): | |
| 172 | + """ add common gnuplot argument to OptParser object """ | |
| 173 | + parser.add_option("-x","--xsize", | |
| 174 | + action="store", dest="xsize", default=1., | |
| 175 | + type='float',help="define xsize for plot") | |
| 176 | + parser.add_option("-y","--ysize", | |
| 177 | + action="store", dest="ysize", default=1., | |
| 178 | + type='float',help="define ysize for plot") | |
| 179 | + parser.add_option("--debug", | |
| 180 | + action="store_true", dest="debug", default=False, | |
| 181 | + help="use gnuplot debug mode") | |
| 182 | + parser.add_option("--persist", | |
| 183 | + action="store_false", dest="persist", default=True, | |
| 184 | + help="do not use gnuplot persistant mode") | |
| 185 | + parser.add_option("--lmargin", | |
| 186 | + action="store", dest="lmargin", default=None, | |
| 187 | + type='int',help="define left margin for plot") | |
| 188 | + parser.add_option("--rmargin", | |
| 189 | + action="store", dest="rmargin", default=None, | |
| 190 | + type='int',help="define right margin for plot") | |
| 191 | + parser.add_option("--bmargin", | |
| 192 | + action="store", dest="bmargin", default=None, | |
| 193 | + type='int',help="define bottom margin for plot") | |
| 194 | + parser.add_option("--tmargin", | |
| 195 | + action="store", dest="tmargin", default=None, | |
| 196 | + type='int',help="define top margin for plot") | |
| 197 | + parser.add_option("-O","--outplot", | |
| 198 | + action="store", dest="outplot", default=None, | |
| 199 | + help="save plot to output.{ps,png}") | |
| 200 | + | |
| 201 | +def gnuplot_create(outplot='',extension='', options=None): | |
| 202 | + import Gnuplot | |
| 203 | + if options: | |
| 204 | + g = Gnuplot.Gnuplot(debug=options.debug, persist=options.persist) | |
| 205 | + else: | |
| 206 | + g = Gnuplot.Gnuplot(persist=1) | |
| 207 | + if not extension or not outplot: return g | |
| 208 | + if extension == 'ps': ext, extension = '.ps' , 'postscript' | |
| 209 | + elif extension == 'eps': ext, extension = '.eps' , 'postscript enhanced' | |
| 210 | + elif extension == 'epsc': ext, extension = '.eps' , 'postscript enhanced color' | |
| 211 | + elif extension == 'png': ext, extension = '.png', 'png' | |
| 212 | + elif extension == 'svg': ext, extension = '.svg', 'svg' | |
| 213 | + else: exit("ERR: unknown plot extension") | |
| 214 | + g('set terminal %s' % extension) | |
| 215 | + if options and options.lmargin: g('set lmargin %i' % options.lmargin) | |
| 216 | + if options and options.rmargin: g('set rmargin %i' % options.rmargin) | |
| 217 | + if options and options.bmargin: g('set bmargin %i' % options.bmargin) | |
| 218 | + if options and options.tmargin: g('set tmargin %i' % options.tmargin) | |
| 219 | + if outplot != "stdout": | |
| 220 | + g('set output \'%s%s\'' % (outplot,ext)) | |
| 221 | + if options: g('set size %f,%f' % (options.xsize, options.ysize)) | |
| 222 | + return g | |
| @@ -0,0 +1,69 @@ | ||
| 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-2009 Paul Brossier <piem@aubio.org> | |
| 7 | + | |
| 8 | + This file is part of aubio. | |
| 9 | + | |
| 10 | + aubio is free software: you can redistribute it and/or modify | |
| 11 | + it under the terms of the GNU General Public License as published by | |
| 12 | + the Free Software Foundation, either version 3 of the License, or | |
| 13 | + (at your option) any later version. | |
| 14 | + | |
| 15 | + aubio is distributed in the hope that it will be useful, | |
| 16 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 17 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 18 | + GNU General Public License for more details. | |
| 19 | + | |
| 20 | + You should have received a copy of the GNU General Public License | |
| 21 | + along with aubio. If not, see <http://www.gnu.org/licenses/>. | |
| 22 | +""" | |
| 23 | + | |
| 24 | +""" | |
| 25 | +original author Tim Peters | |
| 26 | +modified by Paul Brossier <piem@altern.org> | |
| 27 | +inspired from http://www.ics.uci.edu/~eppstein/161/python/peters-selection.py | |
| 28 | +""" | |
| 29 | + | |
| 30 | +def short_find(a, rank): | |
| 31 | + """ find the rank-th value in sorted a """ | |
| 32 | + # copy to b before sorting | |
| 33 | + b = a[:] | |
| 34 | + b.sort() | |
| 35 | + return b[rank - 1] | |
| 36 | + | |
| 37 | +def percental(a, rank): | |
| 38 | + """ Find the rank'th-smallest value in a, in worst-case linear time. """ | |
| 39 | + n = len(a) | |
| 40 | + assert 1 <= rank <= n | |
| 41 | + if n <= 7: | |
| 42 | + return short_find(a, rank) | |
| 43 | + | |
| 44 | + ## Find median of median-of-7's. | |
| 45 | + ##medians = [short_find(a[i : i+7], 4) for i in xrange(0, n-6, 7)] | |
| 46 | + #median = find(medians, (len(medians) + 1) // 2) | |
| 47 | + | |
| 48 | + # modified to Find median | |
| 49 | + median = short_find([a[0], a[-1], a[n//2]], 2) | |
| 50 | + | |
| 51 | + # Partition around the median. | |
| 52 | + # a[:i] <= median | |
| 53 | + # a[j+1:] >= median | |
| 54 | + i, j = 0, n-1 | |
| 55 | + while i <= j: | |
| 56 | + while a[i] < median: | |
| 57 | + i += 1 | |
| 58 | + while a[j] > median: | |
| 59 | + j -= 1 | |
| 60 | + if i <= j: | |
| 61 | + a[i], a[j] = a[j], a[i] | |
| 62 | + i += 1 | |
| 63 | + j -= 1 | |
| 64 | + | |
| 65 | + if rank <= i: | |
| 66 | + return percental(a[:i], rank) | |
| 67 | + else: | |
| 68 | + return percental(a[i:], rank - i) | |
| 69 | + | |
| @@ -0,0 +1,143 @@ | ||
| 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-2009 Paul Brossier <piem@aubio.org> | |
| 7 | + | |
| 8 | + This file is part of aubio. | |
| 9 | + | |
| 10 | + aubio is free software: you can redistribute it and/or modify | |
| 11 | + it under the terms of the GNU General Public License as published by | |
| 12 | + the Free Software Foundation, either version 3 of the License, or | |
| 13 | + (at your option) any later version. | |
| 14 | + | |
| 15 | + aubio is distributed in the hope that it will be useful, | |
| 16 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 17 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 18 | + GNU General Public License for more details. | |
| 19 | + | |
| 20 | + You should have received a copy of the GNU General Public License | |
| 21 | + along with aubio. If not, see <http://www.gnu.org/licenses/>. | |
| 22 | +""" | |
| 23 | + | |
| 24 | +""" this file contains routines to compare two lists of onsets or notes. | |
| 25 | +it somewhat implements the Receiver Operating Statistic (ROC). | |
| 26 | +see http://en.wikipedia.org/wiki/Receiver_operating_characteristic | |
| 27 | +""" | |
| 28 | + | |
| 29 | +def onset_roc(ltru, lexp, eps): | |
| 30 | + """ compute differences between two lists | |
| 31 | + orig = hits + missed + merged | |
| 32 | + expc = hits + bad + doubled | |
| 33 | + returns orig, missed, merged, expc, bad, doubled | |
| 34 | + """ | |
| 35 | + orig, expc = len(ltru), len(lexp) | |
| 36 | + # if lexp is empty | |
| 37 | + if expc == 0 : return orig,orig,0,0,0,0 | |
| 38 | + missed, bad, doubled, merged = 0, 0, 0, 0 | |
| 39 | + # find missed and doubled ones first | |
| 40 | + for x in ltru: | |
| 41 | + correspond = 0 | |
| 42 | + for y in lexp: | |
| 43 | + if abs(x-y) <= eps: correspond += 1 | |
| 44 | + if correspond == 0: missed += 1 | |
| 45 | + elif correspond > 1: doubled += correspond - 1 | |
| 46 | + # then look for bad and merged ones | |
| 47 | + for y in lexp: | |
| 48 | + correspond = 0 | |
| 49 | + for x in ltru: | |
| 50 | + if abs(x-y) <= eps: correspond += 1 | |
| 51 | + if correspond == 0: bad += 1 | |
| 52 | + elif correspond > 1: merged += correspond - 1 | |
| 53 | + # check consistancy of the results | |
| 54 | + assert ( orig - missed - merged == expc - bad - doubled) | |
| 55 | + return orig, missed, merged, expc, bad, doubled | |
| 56 | + | |
| 57 | +def onset_diffs(ltru, lexp, eps): | |
| 58 | + """ compute differences between two lists | |
| 59 | + orig = hits + missed + merged | |
| 60 | + expc = hits + bad + doubled | |
| 61 | + returns orig, missed, merged, expc, bad, doubled | |
| 62 | + """ | |
| 63 | + orig, expc = len(ltru), len(lexp) | |
| 64 | + # if lexp is empty | |
| 65 | + l = [] | |
| 66 | + if expc == 0 : return l | |
| 67 | + # find missed and doubled ones first | |
| 68 | + for x in ltru: | |
| 69 | + correspond = 0 | |
| 70 | + for y in lexp: | |
| 71 | + if abs(x-y) <= eps: l.append(y-x) | |
| 72 | + # return list of diffs | |
| 73 | + return l | |
| 74 | + | |
| 75 | +def onset_rocloc(ltru, lexp, eps): | |
| 76 | + """ compute differences between two lists | |
| 77 | + orig = hits + missed + merged | |
| 78 | + expc = hits + bad + doubled | |
| 79 | + returns orig, missed, merged, expc, bad, doubled | |
| 80 | + """ | |
| 81 | + orig, expc = len(ltru), len(lexp) | |
| 82 | + l = [] | |
| 83 | + labs = [] | |
| 84 | + mean = 0 | |
| 85 | + # if lexp is empty | |
| 86 | + if expc == 0 : return orig,orig,0,0,0,0,l,mean | |
| 87 | + missed, bad, doubled, merged = 0, 0, 0, 0 | |
| 88 | + # find missed and doubled ones first | |
| 89 | + for x in ltru: | |
| 90 | + correspond = 0 | |
| 91 | + for y in lexp: | |
| 92 | + if abs(x-y) <= eps: correspond += 1 | |
| 93 | + if correspond == 0: missed += 1 | |
| 94 | + elif correspond > 1: doubled += correspond - 1 | |
| 95 | + # then look for bad and merged ones | |
| 96 | + for y in lexp: | |
| 97 | + correspond = 0 | |
| 98 | + for x in ltru: | |
| 99 | + if abs(x-y) <= eps: | |
| 100 | + correspond += 1 | |
| 101 | + l.append(y-x) | |
| 102 | + labs.append(abs(y-x)) | |
| 103 | + if correspond == 0: bad += 1 | |
| 104 | + elif correspond > 1: merged += correspond - 1 | |
| 105 | + # check consistancy of the results | |
| 106 | + assert ( orig - missed - merged == expc - bad - doubled) | |
| 107 | + return orig, missed, merged, expc, bad, doubled, l, labs | |
| 108 | + | |
| 109 | +def notes_roc (la, lb, eps): | |
| 110 | + from numpy import transpose, add, resize | |
| 111 | + """ creates a matrix of size len(la)*len(lb) then look for hit and miss | |
| 112 | + in it within eps tolerance windows """ | |
| 113 | + gdn,fpw,fpg,fpa,fdo,fdp = 0,0,0,0,0,0 | |
| 114 | + m = len(la) | |
| 115 | + n = len(lb) | |
| 116 | + x = resize(la[:][0],(n,m)) | |
| 117 | + y = transpose(resize(lb[:][0],(m,n))) | |
| 118 | + teps = (abs(x-y) <= eps[0]) | |
| 119 | + x = resize(la[:][1],(n,m)) | |
| 120 | + y = transpose(resize(lb[:][1],(m,n))) | |
| 121 | + tpitc = (abs(x-y) <= eps[1]) | |
| 122 | + res = teps * tpitc | |
| 123 | + res = add.reduce(res,axis=0) | |
| 124 | + for i in range(len(res)) : | |
| 125 | + if res[i] > 1: | |
| 126 | + gdn+=1 | |
| 127 | + fdo+=res[i]-1 | |
| 128 | + elif res [i] == 1: | |
| 129 | + gdn+=1 | |
| 130 | + fpa = n - gdn - fpa | |
| 131 | + return gdn,fpw,fpg,fpa,fdo,fdp | |
| 132 | + | |
| 133 | +def load_onsets(filename) : | |
| 134 | + """ load onsets targets / candidates files in arrays """ | |
| 135 | + l = []; | |
| 136 | + | |
| 137 | + f = open(filename,'ro') | |
| 138 | + while 1: | |
| 139 | + line = f.readline().split() | |
| 140 | + if not line : break | |
| 141 | + l.append(float(line[0])) | |
| 142 | + | |
| 143 | + return l | |
Empty file added.
| @@ -0,0 +1,46 @@ | ||
| 1 | + | |
| 2 | +def draw_keyboard(firstnote = 21, lastnote = 108, y0 = 0, y1 = 1): | |
| 3 | + import Gnuplot | |
| 4 | + octaves = 10 | |
| 5 | + | |
| 6 | + # build template of white notes | |
| 7 | + scalew = 12/7. | |
| 8 | + xw_temp = [i*scalew for i in range(0,7)] | |
| 9 | + # build template of black notes | |
| 10 | + scaleb = 6/7. | |
| 11 | + xb_temp = [i*scaleb for i in [1,3,7,9,11]] | |
| 12 | + | |
| 13 | + xb,xw = [],[] | |
| 14 | + for octave in range(octaves-1): | |
| 15 | + for i in xb_temp: | |
| 16 | + curnote = i+12*octave | |
| 17 | + if curnote > firstnote-1 and curnote < lastnote+1: | |
| 18 | + xb = xb + [curnote] | |
| 19 | + for octave in range(octaves-1): | |
| 20 | + for i in xw_temp: | |
| 21 | + curnote = i+12*octave | |
| 22 | + if curnote > firstnote-1 and curnote < lastnote+1: | |
| 23 | + xw = xw + [curnote] | |
| 24 | + | |
| 25 | + xwdelta = [1/2. * scalew for i in range(len(xw))] | |
| 26 | + yw = [y0+(y1-y0)*1/2. for i in range(len(xw))] | |
| 27 | + ywdelta = [(y1-y0)*1/2. for i in range(len(xw))] | |
| 28 | + | |
| 29 | + xbdelta = [2/3. * scaleb for i in range(len(xb))] | |
| 30 | + yb = [y0+(y1-y0)*2/3. for i in range(len(xb))] | |
| 31 | + ybdelta = [(y1-y0)*1/3. for i in range(len(xb))] | |
| 32 | + | |
| 33 | + whites = Gnuplot.Data(xw,yw,xwdelta,ywdelta,with_ = 'boxxyerrorbars') | |
| 34 | + blacks = Gnuplot.Data(xb,yb,xbdelta,ybdelta,with_ = 'boxxyerrorbars fill solid') | |
| 35 | + | |
| 36 | + return blacks,whites | |
| 37 | + | |
| 38 | +if __name__ == '__main__': | |
| 39 | + from aubio.gnuplot import gnuplot_create | |
| 40 | + blacks,whites = draw_keyboard(firstnote = 21, lastnote = 108) | |
| 41 | + g = gnuplot_create('','') | |
| 42 | + #g('set style fill solid .5') | |
| 43 | + #g('set xrange [60-.5:72+.5]') | |
| 44 | + #g('set yrange [-0.1:1.1]') | |
| 45 | + | |
| 46 | + g.plot(whites,blacks) | |
| @@ -0,0 +1,90 @@ | ||
| 1 | +__LICENSE__ = """\ | |
| 2 | + Copyright (C) 2004-2009 Paul Brossier <piem@aubio.org> | |
| 3 | + | |
| 4 | + This file is part of aubio. | |
| 5 | + | |
| 6 | + aubio is free software: you can redistribute it and/or modify | |
| 7 | + it under the terms of the GNU General Public License as published by | |
| 8 | + the Free Software Foundation, either version 3 of the License, or | |
| 9 | + (at your option) any later version. | |
| 10 | + | |
| 11 | + aubio is distributed in the hope that it will be useful, | |
| 12 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | + GNU General Public License for more details. | |
| 15 | + | |
| 16 | + You should have received a copy of the GNU General Public License | |
| 17 | + along with aubio. If not, see <http://www.gnu.org/licenses/>. | |
| 18 | +""" | |
| 19 | + | |
| 20 | +def plotnote(la,title=None) : | |
| 21 | + if la[0,:].size() == 3: | |
| 22 | + d = plotnote_withends(la, plot_title=title) | |
| 23 | + else: | |
| 24 | + # scale data if in freq (for REF.txt files) | |
| 25 | + if max(la[:,1] > 128 ): | |
| 26 | + print "scaling frequency data to midi range" | |
| 27 | + la[:,1] /= 6.875 | |
| 28 | + la[:,1] = log(la[:,1])/0.6931 | |
| 29 | + la[:,1] *= 12 | |
| 30 | + la[:,1] -= 3 | |
| 31 | + d = plotnote_withoutends(la, plot_title=title) | |
| 32 | + return d | |
| 33 | + | |
| 34 | +def plotnote_multi(lalist,title=None,fileout=None) : | |
| 35 | + d=list() | |
| 36 | + for i in range(len(lalist)): | |
| 37 | + d.append(plotnote(lalist[i], title=title)) | |
| 38 | + return d | |
| 39 | + | |
| 40 | + | |
| 41 | +def plotnote_withends(la,plot_title=None) : | |
| 42 | + from numpy import array | |
| 43 | + import Gnuplot, Gnuplot.funcutils | |
| 44 | + d=[] | |
| 45 | + x_widths = array(la[:,1]-la[:,0])/2. | |
| 46 | + d.append(Gnuplot.Data( | |
| 47 | + la[:,0]+x_widths, # x centers | |
| 48 | + la[:,2], # y centers | |
| 49 | + x_widths, # x errors | |
| 50 | + __notesheight*ones(len(la)), # y errors | |
| 51 | + title=plot_title,with_=('boxxyerrorbars fs 3'))) | |
| 52 | + return d | |
| 53 | + | |
| 54 | + | |
| 55 | +def plotnote_withoutends(la,plot_title=None) : | |
| 56 | + """ bug: fails drawing last note """ | |
| 57 | + from numpy import array | |
| 58 | + import Gnuplot, Gnuplot.funcutils | |
| 59 | + d=[] | |
| 60 | + x_widths = array(la[1:,0]-la[:-1,0])/2; | |
| 61 | + d.append(Gnuplot.Data( | |
| 62 | + la[:-1,0]+x_widths, # x centers | |
| 63 | + la[:-1,1], # y centers | |
| 64 | + x_widths, # x errors | |
| 65 | + __notesheight*ones(len(la)-1), # y errors | |
| 66 | + title=plot_title,with_=('boxxyerrorbars fs 3'))) | |
| 67 | + return d | |
| 68 | + | |
| 69 | +def plotnote_do(d,fileout=None): | |
| 70 | + import Gnuplot, Gnuplot.funcutils | |
| 71 | + g = Gnuplot.Gnuplot(debug=1, persist=1) | |
| 72 | + g.gnuplot('set style fill solid border 1; \ | |
| 73 | + set size ratio 1/6; \ | |
| 74 | + set boxwidth 0.9 relative; \ | |
| 75 | + set mxtics 2.5; \ | |
| 76 | + set mytics 2.5; \ | |
| 77 | + set xtics 5; \ | |
| 78 | + set ytics 1; \ | |
| 79 | + set grid xtics ytics mxtics mytics') | |
| 80 | + | |
| 81 | + g.xlabel('Time (s)') | |
| 82 | + g.ylabel('Midi pitch') | |
| 83 | + # do the plot | |
| 84 | + #g.gnuplot('set multiplot') | |
| 85 | + #for i in d: | |
| 86 | + g.plot(d[0]) | |
| 87 | + #g.gnuplot('set nomultiplot') | |
| 88 | + if fileout != None: | |
| 89 | + g.hardcopy(fileout, enhanced=1, color=0) | |
| 90 | + | |
| @@ -0,0 +1,9 @@ | ||
| 1 | +from aubio.aubioclass import * | |
| 2 | +from aubio.task.task import task | |
| 3 | +from aubio.task.params import taskparams | |
| 4 | +from aubio.task.silence import tasksilence | |
| 5 | +from aubio.task.onset import taskonset | |
| 6 | +from aubio.task.beat import taskbeat | |
| 7 | +from aubio.task.cut import taskcut | |
| 8 | +from aubio.task.pitch import taskpitch | |
| 9 | +from aubio.task.notes import tasknotes | |
| @@ -0,0 +1,262 @@ | ||
| 1 | +from aubio.aubioclass import * | |
| 2 | +from onset import taskonset | |
| 3 | + | |
| 4 | +class taskbeat(taskonset): | |
| 5 | + def __init__(self,input,params=None,output=None): | |
| 6 | + """ open the input file and initialize arguments | |
| 7 | + parameters should be set *before* calling this method. | |
| 8 | + """ | |
| 9 | + taskonset.__init__(self,input,output=None,params=params) | |
| 10 | + self.btwinlen = 512**2/self.params.hopsize | |
| 11 | + self.btstep = self.btwinlen/4 | |
| 12 | + self.btoutput = fvec(self.btstep,self.channels) | |
| 13 | + self.dfframe = fvec(self.btwinlen,self.channels) | |
| 14 | + self.bt = beattracking(self.btwinlen,self.channels) | |
| 15 | + self.pos2 = 0 | |
| 16 | + self.old = -1000 | |
| 17 | + | |
| 18 | + def __call__(self): | |
| 19 | + taskonset.__call__(self) | |
| 20 | + #results = taskonset.__call__(self) | |
| 21 | + # write to current file | |
| 22 | + if self.pos2 == self.btstep - 1 : | |
| 23 | + self.bt.do(self.dfframe,self.btoutput) | |
| 24 | + for i in range (self.btwinlen - self.btstep): | |
| 25 | + self.dfframe.set(self.dfframe.get(i+self.btstep,0),i,0) | |
| 26 | + for i in range(self.btwinlen - self.btstep, self.btwinlen): | |
| 27 | + self.dfframe.set(0,i,0) | |
| 28 | + self.pos2 = -1; | |
| 29 | + self.pos2 += 1 | |
| 30 | + val = self.opick.pp.getval() | |
| 31 | + #if not results: val = 0 | |
| 32 | + #else: val = results[1] | |
| 33 | + self.dfframe.set(val,self.btwinlen - self.btstep + self.pos2,0) | |
| 34 | + i=0 | |
| 35 | + for i in range(1,int( self.btoutput.get(0,0) ) ): | |
| 36 | + if self.pos2 == self.btoutput.get(i,0) and \ | |
| 37 | + aubio_silence_detection(self.myvec(), | |
| 38 | + self.params.silence)!=1: | |
| 39 | + now = self.frameread-0 | |
| 40 | + period = (60 * self.params.samplerate) / ((now - self.old) * self.params.hopsize) | |
| 41 | + self.old = now | |
| 42 | + return now,period | |
| 43 | + | |
| 44 | + def eval(self,results,tol=0.20,tolcontext=0.25): | |
| 45 | + obeats = self.gettruth() | |
| 46 | + etime = [result[0] for result in results] | |
| 47 | + otime = [obeat[0] for obeat in obeats] | |
| 48 | + CML_tot, CML_max, CML_start, CML_end = 0,0,0,0 | |
| 49 | + AML_tot, AML_max, AML_start, AML_end = 0,0,0,0 | |
| 50 | + AMLd_tot, AMLd_max, AMLd_start, AMLd_end = 0,0,0,0 | |
| 51 | + AMLh_tot, AMLh_max, AMLh_start, AMLh_end = 0,0,0,0 | |
| 52 | + AMLo_tot, AMLo_max, AMLo_start, AMLo_end = 0,0,0,0 | |
| 53 | + # results iteration | |
| 54 | + j = 1 | |
| 55 | + # for each annotation | |
| 56 | + for i in range(2,len(otime)-2): | |
| 57 | + if j+1 >= len(etime): break | |
| 58 | + count = 0 | |
| 59 | + # look for next matching beat | |
| 60 | + while otime[i] > etime[j] - (otime[i] - otime[i+1])*tol: | |
| 61 | + if count > 0: | |
| 62 | + #print "spurious etime" | |
| 63 | + if CML_end - CML_start > CML_max: | |
| 64 | + CML_max = CML_end - CML_start | |
| 65 | + CML_start, CML_end = j, j | |
| 66 | + if AMLh_end - AMLh_start > AMLh_max: | |
| 67 | + AMLh_max = AMLh_end - AMLh_start | |
| 68 | + AMLh_start, AMLh_end = j, j | |
| 69 | + if AMLd_end - AMLd_start > AMLd_max: | |
| 70 | + AMLd_max = AMLd_end - AMLd_start | |
| 71 | + AMLd_start, AMLd_end = j, j | |
| 72 | + if AMLo_end - AMLo_start > AMLo_max: | |
| 73 | + AMLo_max = AMLo_end - AMLo_start | |
| 74 | + AMLo_start, AMLo_end = j, j | |
| 75 | + j += 1 | |
| 76 | + count += 1 | |
| 77 | + if j+1 >= len(etime): break | |
| 78 | + #print otime[i-1],etime[j-1]," ",otime[i],etime[j]," ",otime[i+1],etime[j+1] | |
| 79 | + prevtempo = (otime[i] - otime[i-1]) | |
| 80 | + nexttempo = (otime[i+1] - otime[i]) | |
| 81 | + | |
| 82 | + current0 = (etime[j] > otime[i] - prevtempo*tol) | |
| 83 | + current1 = (etime[j] < otime[i] + prevtempo*tol) | |
| 84 | + | |
| 85 | + # check correct tempo | |
| 86 | + prev0 = (etime[j-1] > otime[i-1] - prevtempo*tolcontext) | |
| 87 | + prev1 = (etime[j-1] < otime[i-1] + prevtempo*tolcontext) | |
| 88 | + next0 = (etime[j+1] > otime[i+1] - nexttempo*tolcontext) | |
| 89 | + next1 = (etime[j+1] < otime[i+1] + nexttempo*tolcontext) | |
| 90 | + | |
| 91 | + # check for off beat | |
| 92 | + prevoffb0 = (etime[j-1] > otime[i-1] - prevtempo/2 - prevtempo*tolcontext) | |
| 93 | + prevoffb1 = (etime[j-1] < otime[i-1] - prevtempo/2 + prevtempo*tolcontext) | |
| 94 | + nextoffb0 = (etime[j+1] > otime[i+1] - nexttempo/2 - nexttempo*tolcontext) | |
| 95 | + nextoffb1 = (etime[j+1] < otime[i+1] - nexttempo/2 + nexttempo*tolcontext) | |
| 96 | + | |
| 97 | + # check half tempo | |
| 98 | + prevhalf0 = (etime[j-1] > otime[i-1] + prevtempo - prevtempo/2*tolcontext) | |
| 99 | + prevhalf1 = (etime[j-1] < otime[i-1] + prevtempo + prevtempo/2*tolcontext) | |
| 100 | + nexthalf0 = (etime[j+1] > otime[i+1] - nexttempo - nexttempo/2*tolcontext) | |
| 101 | + nexthalf1 = (etime[j+1] < otime[i+1] - nexttempo + nexttempo/2*tolcontext) | |
| 102 | + | |
| 103 | + # check double tempo | |
| 104 | + prevdoub0 = (etime[j-1] > otime[i-1] - prevtempo - prevtempo*2*tolcontext) | |
| 105 | + prevdoub1 = (etime[j-1] < otime[i-1] - prevtempo + prevtempo*2*tolcontext) | |
| 106 | + nextdoub0 = (etime[j+1] > otime[i+1] + nexttempo - nexttempo*2*tolcontext) | |
| 107 | + nextdoub1 = (etime[j+1] < otime[i+1] + nexttempo + nexttempo*2*tolcontext) | |
| 108 | + | |
| 109 | + if current0 and current1 and prev0 and prev1 and next0 and next1: | |
| 110 | + #print "YES!" | |
| 111 | + CML_end = j | |
| 112 | + CML_tot += 1 | |
| 113 | + else: | |
| 114 | + if CML_end - CML_start > CML_max: | |
| 115 | + CML_max = CML_end - CML_start | |
| 116 | + CML_start, CML_end = j, j | |
| 117 | + if current0 and current1 and prevhalf0 and prevhalf1 and nexthalf0 and nexthalf1: | |
| 118 | + AMLh_end = j | |
| 119 | + AMLh_tot += 1 | |
| 120 | + else: | |
| 121 | + if AMLh_end - AMLh_start > AMLh_max: | |
| 122 | + AMLh_max = AMLh_end - AMLh_start | |
| 123 | + AMLh_start, AMLh_end = j, j | |
| 124 | + if current0 and current1 and prevdoub0 and prevdoub1 and nextdoub0 and nextdoub1: | |
| 125 | + AMLd_end = j | |
| 126 | + AMLd_tot += 1 | |
| 127 | + else: | |
| 128 | + if AMLd_end - AMLd_start > AMLd_max: | |
| 129 | + AMLd_max = AMLd_end - AMLd_start | |
| 130 | + AMLd_start, AMLd_end = j, j | |
| 131 | + if current0 and current1 and prevoffb0 and prevoffb1 and nextoffb0 and nextoffb1: | |
| 132 | + AMLo_end = j | |
| 133 | + AMLo_tot += 1 | |
| 134 | + else: | |
| 135 | + if AMLo_end - AMLo_start > AMLo_max: | |
| 136 | + AMLo_max = AMLo_end - AMLo_start | |
| 137 | + AMLo_start, AMLo_end = j, j | |
| 138 | + # look for next matching beat | |
| 139 | + count = 0 | |
| 140 | + while otime[i] > etime[j] - (otime[i] - otime[i+1])*tolcontext: | |
| 141 | + j += 1 | |
| 142 | + if count > 0: | |
| 143 | + #print "spurious etime" | |
| 144 | + start = j | |
| 145 | + count += 1 | |
| 146 | + total = float(len(otime)) | |
| 147 | + CML_tot /= total | |
| 148 | + AMLh_tot /= total | |
| 149 | + AMLd_tot /= total | |
| 150 | + AMLo_tot /= total | |
| 151 | + CML_cont = CML_max/total | |
| 152 | + AMLh_cont = AMLh_max/total | |
| 153 | + AMLd_cont = AMLd_max/total | |
| 154 | + AMLo_cont = AMLo_max/total | |
| 155 | + return CML_cont, CML_tot, AMLh_cont, AMLh_tot, AMLd_cont, AMLd_tot, AMLo_cont, AMLo_tot | |
| 156 | + | |
| 157 | +# for i in allfreq: | |
| 158 | +# freq.append(float(i) / 2. / N * samplerate ) | |
| 159 | +# while freq[i]>freqs[j]: | |
| 160 | +# j += 1 | |
| 161 | +# a0 = weight[j-1] | |
| 162 | +# a1 = weight[j] | |
| 163 | +# f0 = freqs[j-1] | |
| 164 | +# f1 = freqs[j] | |
| 165 | +# if f0!=0: | |
| 166 | +# iweight.append((a1-a0)/(f1-f0)*freq[i] + (a0 - (a1 - a0)/(f1/f0 -1.))) | |
| 167 | +# else: | |
| 168 | +# iweight.append((a1-a0)/(f1-f0)*freq[i] + a0) | |
| 169 | +# while freq[i]>freqs[j]: | |
| 170 | +# j += 1 | |
| 171 | + | |
| 172 | + def eval2(self,results,tol=0.2): | |
| 173 | + truth = self.gettruth() | |
| 174 | + obeats = [i[0] for i in truth] | |
| 175 | + ebeats = [i[0]*self.params.step for i in results] | |
| 176 | + NP = max(len(obeats), len(ebeats)) | |
| 177 | + N = int(round(max(max(obeats), max(ebeats))*100.)+100) | |
| 178 | + W = int(round(tol*100.*60./median([i[1] for i in truth], len(truth)/2))) | |
| 179 | + ofunc = [0 for i in range(N+W)] | |
| 180 | + efunc = [0 for i in range(N+W)] | |
| 181 | + for i in obeats: ofunc[int(round(i*100.)+W)] = 1 | |
| 182 | + for i in ebeats: efunc[int(round(i*100.)+W)] = 1 | |
| 183 | + assert len(obeats) == sum(ofunc) | |
| 184 | + autocor = 0; m =0 | |
| 185 | + for m in range (-W, W): | |
| 186 | + for i in range(W,N): | |
| 187 | + autocor += ofunc[i] * efunc[i-m] | |
| 188 | + autocor /= float(NP) | |
| 189 | + return autocor | |
| 190 | + | |
| 191 | + def evaluation(self,results,tol=0.2,start=5.): | |
| 192 | + | |
| 193 | + """ beat tracking evaluation function | |
| 194 | + | |
| 195 | + computes P-score of experimental results (ebeats) | |
| 196 | + against ground truth annotations (obeats) """ | |
| 197 | + | |
| 198 | + from aubio.median import short_find as median | |
| 199 | + truth = self.gettruth() | |
| 200 | + ebeats = [i[0]*self.params.step for i in results] | |
| 201 | + obeats = [i[0] for i in truth] | |
| 202 | + | |
| 203 | + # trim anything found before start | |
| 204 | + while obeats[0] < start: obeats.pop(0) | |
| 205 | + while ebeats[0] < start: ebeats.pop(0) | |
| 206 | + # maximum number of beats found | |
| 207 | + NP = max(len(obeats), len(ebeats)) | |
| 208 | + # length of ofunc and efunc vector | |
| 209 | + N = int(round(max(max(obeats), max(ebeats))*100.)+100) | |
| 210 | + # compute W median of ground truth tempi | |
| 211 | + tempi = [] | |
| 212 | + for i in range(1,len(obeats)): tempi.append(obeats[i]-obeats[i-1]) | |
| 213 | + W = int(round(tol*100.*median(tempi,len(tempi)/2))) | |
| 214 | + # build ofunc and efunc functions, starting with W zeros | |
| 215 | + ofunc = [0 for i in range(N+W)] | |
| 216 | + efunc = [0 for i in range(N+W)] | |
| 217 | + for i in obeats: ofunc[int(round(i*100.)+W)] = 1 | |
| 218 | + for i in ebeats: efunc[int(round(i*100.)+W)] = 1 | |
| 219 | + # optional: make sure we didn't miss any beats | |
| 220 | + assert len(obeats) == sum(ofunc) | |
| 221 | + assert len(ebeats) == sum(efunc) | |
| 222 | + # compute auto correlation | |
| 223 | + autocor = 0; m =0 | |
| 224 | + for m in range (-W, W): | |
| 225 | + for i in range(W,N): | |
| 226 | + autocor += ofunc[i] * efunc[i-m] | |
| 227 | + autocor /= float(NP) | |
| 228 | + return autocor | |
| 229 | + | |
| 230 | + def gettruth(self): | |
| 231 | + import os.path | |
| 232 | + from aubio.txtfile import read_datafile | |
| 233 | + datafile = self.input.replace('.wav','.txt') | |
| 234 | + if not os.path.isfile(datafile): | |
| 235 | + print "no ground truth " | |
| 236 | + return False,False | |
| 237 | + else: | |
| 238 | + values = read_datafile(datafile,depth=0) | |
| 239 | + old = -1000 | |
| 240 | + for i in range(len(values)): | |
| 241 | + now = values[i] | |
| 242 | + period = 60 / (now - old) | |
| 243 | + old = now | |
| 244 | + values[i] = [now,period] | |
| 245 | + return values | |
| 246 | + | |
| 247 | + | |
| 248 | + def plot(self,oplots,results): | |
| 249 | + import Gnuplot | |
| 250 | + oplots.append(Gnuplot.Data(results,with_='linespoints',title="auto")) | |
| 251 | + | |
| 252 | + def plotplot(self,wplot,oplots,outplot=None,extension=None,xsize=1.,ysize=1.,spectro=False): | |
| 253 | + import Gnuplot | |
| 254 | + from aubio.gnuplot import gnuplot_create, audio_to_array, make_audio_plot | |
| 255 | + import re | |
| 256 | + # audio data | |
| 257 | + #time,data = audio_to_array(self.input) | |
| 258 | + #f = make_audio_plot(time,data) | |
| 259 | + | |
| 260 | + g = gnuplot_create(outplot=outplot, extension=extension) | |
| 261 | + oplots = [Gnuplot.Data(self.gettruth(),with_='linespoints',title="orig")] + oplots | |
| 262 | + g.plot(*oplots) | |
| @@ -0,0 +1,42 @@ | ||
| 1 | +from task import task | |
| 2 | +from aubio.aubioclass import * | |
| 3 | + | |
| 4 | +class taskcut(task): | |
| 5 | + def __init__(self,input,slicetimes,params=None,output=None): | |
| 6 | + """ open the input file and initialize arguments | |
| 7 | + parameters should be set *before* calling this method. | |
| 8 | + """ | |
| 9 | + from os.path import basename,splitext | |
| 10 | + task.__init__(self,input,output=None,params=params) | |
| 11 | + self.soundoutbase, self.soundoutext = splitext(basename(self.input)) | |
| 12 | + self.newname = "%s%s%09.5f%s%s" % (self.soundoutbase,".", | |
| 13 | + self.frameread*self.params.step,".",self.soundoutext) | |
| 14 | + self.fileo = sndfile(self.newname,model=self.filei) | |
| 15 | + self.myvec = fvec(self.params.hopsize,self.channels) | |
| 16 | + self.mycopy = fvec(self.params.hopsize,self.channels) | |
| 17 | + self.slicetimes = slicetimes | |
| 18 | + | |
| 19 | + def __call__(self): | |
| 20 | + task.__call__(self) | |
| 21 | + # write to current file | |
| 22 | + if len(self.slicetimes) and self.frameread >= self.slicetimes[0][0]: | |
| 23 | + self.slicetimes.pop(0) | |
| 24 | + # write up to 1st zero crossing | |
| 25 | + zerocross = 0 | |
| 26 | + while ( abs( self.myvec.get(zerocross,0) ) > self.params.zerothres ): | |
| 27 | + zerocross += 1 | |
| 28 | + writesize = self.fileo.write(zerocross,self.myvec) | |
| 29 | + fromcross = 0 | |
| 30 | + while (zerocross < self.readsize): | |
| 31 | + for i in range(self.channels): | |
| 32 | + self.mycopy.set(self.myvec.get(zerocross,i),fromcross,i) | |
| 33 | + fromcross += 1 | |
| 34 | + zerocross += 1 | |
| 35 | + del self.fileo | |
| 36 | + self.fileo = sndfile("%s%s%09.5f%s%s" % (self.soundoutbase,".", | |
| 37 | + self.frameread*self.params.step,".",self.soundoutext),model=self.filei) | |
| 38 | + writesize = self.fileo.write(fromcross,self.mycopy) | |
| 39 | + else: | |
| 40 | + writesize = self.fileo.write(self.readsize,self.myvec) | |
| 41 | + | |
| 42 | + | |
| @@ -0,0 +1,159 @@ | ||
| 1 | + | |
| 2 | +from aubio.task import task | |
| 3 | +from aubio.aubioclass import * | |
| 4 | + | |
| 5 | +class tasknotes(task): | |
| 6 | + def __init__(self,input,output=None,params=None): | |
| 7 | + task.__init__(self,input,params=params) | |
| 8 | + self.opick = onsetpick(self.params.bufsize, | |
| 9 | + self.params.hopsize, | |
| 10 | + self.channels, | |
| 11 | + self.myvec, | |
| 12 | + self.params.threshold, | |
| 13 | + mode=self.params.onsetmode, | |
| 14 | + dcthreshold=self.params.dcthreshold, | |
| 15 | + derivate=self.params.derivate) | |
| 16 | + self.pitchdet = pitch(mode=self.params.pitchmode, | |
| 17 | + bufsize=self.params.pbufsize, | |
| 18 | + hopsize=self.params.phopsize, | |
| 19 | + channels=self.channels, | |
| 20 | + samplerate=self.srate, | |
| 21 | + omode=self.params.omode) | |
| 22 | + self.olist = [] | |
| 23 | + self.ofunc = [] | |
| 24 | + self.maxofunc = 0 | |
| 25 | + self.last = -1000 | |
| 26 | + self.oldifreq = 0 | |
| 27 | + if self.params.localmin: | |
| 28 | + self.ovalist = [0., 0., 0., 0., 0.] | |
| 29 | + | |
| 30 | + def __call__(self): | |
| 31 | + from aubio.median import short_find | |
| 32 | + task.__call__(self) | |
| 33 | + isonset,val = self.opick.do(self.myvec) | |
| 34 | + if (aubio_silence_detection(self.myvec(),self.params.silence)): | |
| 35 | + isonset=0 | |
| 36 | + freq = -1. | |
| 37 | + else: | |
| 38 | + freq = self.pitchdet(self.myvec) | |
| 39 | + minpitch = self.params.pitchmin | |
| 40 | + maxpitch = self.params.pitchmax | |
| 41 | + if maxpitch and freq > maxpitch : | |
| 42 | + freq = -1. | |
| 43 | + elif minpitch and freq < minpitch : | |
| 44 | + freq = -1. | |
| 45 | + freq = aubio_freqtomidi(freq) | |
| 46 | + if self.params.pitchsmooth: | |
| 47 | + self.shortlist.append(freq) | |
| 48 | + self.shortlist.pop(0) | |
| 49 | + smoothfreq = short_find(self.shortlist, | |
| 50 | + len(self.shortlist)/2) | |
| 51 | + freq = smoothfreq | |
| 52 | + now = self.frameread | |
| 53 | + ifreq = int(round(freq)) | |
| 54 | + if self.oldifreq == ifreq: | |
| 55 | + self.oldifreq = ifreq | |
| 56 | + else: | |
| 57 | + self.oldifreq = ifreq | |
| 58 | + ifreq = 0 | |
| 59 | + # take back delay | |
| 60 | + if self.params.delay != 0.: now -= self.params.delay | |
| 61 | + if now < 0 : | |
| 62 | + now = 0 | |
| 63 | + if (isonset == 1): | |
| 64 | + if self.params.mintol: | |
| 65 | + # prune doubled | |
| 66 | + if (now - self.last) > self.params.mintol: | |
| 67 | + self.last = now | |
| 68 | + return now, 1, freq, ifreq | |
| 69 | + else: | |
| 70 | + return now, 0, freq, ifreq | |
| 71 | + else: | |
| 72 | + return now, 1, freq, ifreq | |
| 73 | + else: | |
| 74 | + return now, 0, freq, ifreq | |
| 75 | + | |
| 76 | + | |
| 77 | + def fprint(self,foo): | |
| 78 | + print self.params.step*foo[0], foo[1], foo[2], foo[3] | |
| 79 | + | |
| 80 | + def compute_all(self): | |
| 81 | + """ Compute data """ | |
| 82 | + now, onset, freq, ifreq = [], [], [], [] | |
| 83 | + while(self.readsize==self.params.hopsize): | |
| 84 | + n, o, f, i = self() | |
| 85 | + now.append(n*self.params.step) | |
| 86 | + onset.append(o) | |
| 87 | + freq.append(f) | |
| 88 | + ifreq.append(i) | |
| 89 | + if self.params.verbose: | |
| 90 | + self.fprint((n,o,f,i)) | |
| 91 | + return now, onset, freq, ifreq | |
| 92 | + | |
| 93 | + def plot(self,now,onset,freq,ifreq,oplots): | |
| 94 | + import Gnuplot | |
| 95 | + | |
| 96 | + oplots.append(Gnuplot.Data(now,freq,with_='lines', | |
| 97 | + title=self.params.pitchmode)) | |
| 98 | + oplots.append(Gnuplot.Data(now,ifreq,with_='lines', | |
| 99 | + title=self.params.pitchmode)) | |
| 100 | + | |
| 101 | + temponsets = [] | |
| 102 | + for i in onset: | |
| 103 | + temponsets.append(i*1000) | |
| 104 | + oplots.append(Gnuplot.Data(now,temponsets,with_='impulses', | |
| 105 | + title=self.params.pitchmode)) | |
| 106 | + | |
| 107 | + def plotplot(self,wplot,oplots,outplot=None,multiplot = 0): | |
| 108 | + from aubio.gnuplot import gnuplot_init, audio_to_array, make_audio_plot | |
| 109 | + import re | |
| 110 | + import Gnuplot | |
| 111 | + # audio data | |
| 112 | + time,data = audio_to_array(self.input) | |
| 113 | + f = make_audio_plot(time,data) | |
| 114 | + | |
| 115 | + # check if ground truth exists | |
| 116 | + #timet,pitcht = self.gettruth() | |
| 117 | + #if timet and pitcht: | |
| 118 | + # oplots = [Gnuplot.Data(timet,pitcht,with_='lines', | |
| 119 | + # title='ground truth')] + oplots | |
| 120 | + | |
| 121 | + t = Gnuplot.Data(0,0,with_='impulses') | |
| 122 | + | |
| 123 | + g = gnuplot_init(outplot) | |
| 124 | + g('set title \'%s\'' % (re.sub('.*/','',self.input))) | |
| 125 | + g('set multiplot') | |
| 126 | + # hack to align left axis | |
| 127 | + g('set lmargin 15') | |
| 128 | + # plot waveform and onsets | |
| 129 | + g('set size 1,0.3') | |
| 130 | + g('set origin 0,0.7') | |
| 131 | + g('set xrange [0:%f]' % max(time)) | |
| 132 | + g('set yrange [-1:1]') | |
| 133 | + g.ylabel('amplitude') | |
| 134 | + g.plot(f) | |
| 135 | + g('unset title') | |
| 136 | + # plot onset detection function | |
| 137 | + | |
| 138 | + | |
| 139 | + g('set size 1,0.7') | |
| 140 | + g('set origin 0,0') | |
| 141 | + g('set xrange [0:%f]' % max(time)) | |
| 142 | + g('set yrange [20:100]') | |
| 143 | + g('set key right top') | |
| 144 | + g('set noclip one') | |
| 145 | + #g('set format x ""') | |
| 146 | + #g('set log y') | |
| 147 | + #g.xlabel('time (s)') | |
| 148 | + g.ylabel('f0 (Hz)') | |
| 149 | + if multiplot: | |
| 150 | + for i in range(len(oplots)): | |
| 151 | + # plot onset detection functions | |
| 152 | + g('set size 1,%f' % (0.7/(len(oplots)))) | |
| 153 | + g('set origin 0,%f' % (float(i)*0.7/(len(oplots)))) | |
| 154 | + g('set xrange [0:%f]' % max(time)) | |
| 155 | + g.plot(oplots[i]) | |
| 156 | + else: | |
| 157 | + g.plot(*oplots) | |
| 158 | + #g('unset multiplot') | |
| 159 | + | |
| @@ -0,0 +1,220 @@ | ||
| 1 | +from aubio.task.task import task | |
| 2 | +from aubio.aubioclass import * | |
| 3 | + | |
| 4 | +class taskonset(task): | |
| 5 | + def __init__(self,input,output=None,params=None): | |
| 6 | + """ open the input file and initialize arguments | |
| 7 | + parameters should be set *before* calling this method. | |
| 8 | + """ | |
| 9 | + task.__init__(self,input,params=params) | |
| 10 | + self.opick = onsetpick(self.params.bufsize, | |
| 11 | + self.params.hopsize, | |
| 12 | + self.myvec, | |
| 13 | + self.params.threshold, | |
| 14 | + mode=self.params.onsetmode, | |
| 15 | + dcthreshold=self.params.dcthreshold, | |
| 16 | + derivate=self.params.derivate) | |
| 17 | + self.olist = [] | |
| 18 | + self.ofunc = [] | |
| 19 | + self.maxofunc = 0 | |
| 20 | + self.last = 0 | |
| 21 | + if self.params.localmin: | |
| 22 | + self.ovalist = [0., 0., 0., 0., 0.] | |
| 23 | + | |
| 24 | + def __call__(self): | |
| 25 | + task.__call__(self) | |
| 26 | + isonset,val = self.opick.do(self.myvec) | |
| 27 | + if (aubio_silence_detection(self.myvec(),self.params.silence)): | |
| 28 | + isonset=0 | |
| 29 | + if self.params.storefunc: | |
| 30 | + self.ofunc.append(val) | |
| 31 | + if self.params.localmin: | |
| 32 | + if val > 0: self.ovalist.append(val) | |
| 33 | + else: self.ovalist.append(0) | |
| 34 | + self.ovalist.pop(0) | |
| 35 | + if (isonset > 0.): | |
| 36 | + if self.params.localmin: | |
| 37 | + # find local minima before peak | |
| 38 | + i=len(self.ovalist)-1 | |
| 39 | + while self.ovalist[i-1] < self.ovalist[i] and i > 0: | |
| 40 | + i -= 1 | |
| 41 | + now = (self.frameread+1-i) | |
| 42 | + else: | |
| 43 | + now = self.frameread | |
| 44 | + # take back delay | |
| 45 | + if self.params.delay != 0.: now -= self.params.delay | |
| 46 | + if now < 0 : | |
| 47 | + now = 0 | |
| 48 | + if self.params.mintol: | |
| 49 | + # prune doubled | |
| 50 | + if (now - self.last) > self.params.mintol: | |
| 51 | + self.last = now | |
| 52 | + return now, val | |
| 53 | + else: | |
| 54 | + return now, val | |
| 55 | + | |
| 56 | + | |
| 57 | + def fprint(self,foo): | |
| 58 | + print self.params.step*foo[0] | |
| 59 | + | |
| 60 | + def eval(self,inputdata,ftru,mode='roc',vmode=''): | |
| 61 | + from aubio.txtfile import read_datafile | |
| 62 | + from aubio.onsetcompare import onset_roc, onset_diffs, onset_rocloc | |
| 63 | + ltru = read_datafile(ftru,depth=0) | |
| 64 | + lres = [] | |
| 65 | + for i in range(len(inputdata)): lres.append(inputdata[i][0]*self.params.step) | |
| 66 | + if vmode=='verbose': | |
| 67 | + print "Running with mode %s" % self.params.onsetmode, | |
| 68 | + print " and threshold %f" % self.params.threshold, | |
| 69 | + print " on file", self.input | |
| 70 | + #print ltru; print lres | |
| 71 | + if mode == 'local': | |
| 72 | + l = onset_diffs(ltru,lres,self.params.tol) | |
| 73 | + mean = 0 | |
| 74 | + for i in l: mean += i | |
| 75 | + if len(l): mean = "%.3f" % (mean/len(l)) | |
| 76 | + else: mean = "?0" | |
| 77 | + return l, mean | |
| 78 | + elif mode == 'roc': | |
| 79 | + self.orig, self.missed, self.merged, \ | |
| 80 | + self.expc, self.bad, self.doubled = \ | |
| 81 | + onset_roc(ltru,lres,self.params.tol) | |
| 82 | + elif mode == 'rocloc': | |
| 83 | + self.v = {} | |
| 84 | + self.v['orig'], self.v['missed'], self.v['Tm'], \ | |
| 85 | + self.v['expc'], self.v['bad'], self.v['Td'], \ | |
| 86 | + self.v['l'], self.v['labs'] = \ | |
| 87 | + onset_rocloc(ltru,lres,self.params.tol) | |
| 88 | + | |
| 89 | + def plot(self,onsets,ofunc,wplot,oplots,nplot=False): | |
| 90 | + import Gnuplot, Gnuplot.funcutils | |
| 91 | + import aubio.txtfile | |
| 92 | + import os.path | |
| 93 | + from numpy import arange, array, ones | |
| 94 | + from aubio.onsetcompare import onset_roc | |
| 95 | + | |
| 96 | + x1,y1,y1p = [],[],[] | |
| 97 | + oplot = [] | |
| 98 | + if self.params.onsetmode in ('mkl','kl'): ofunc[0:10] = [0] * 10 | |
| 99 | + | |
| 100 | + self.lenofunc = len(ofunc) | |
| 101 | + self.maxofunc = max(ofunc) | |
| 102 | + # onset detection function | |
| 103 | + downtime = arange(len(ofunc))*self.params.step | |
| 104 | + oplot.append(Gnuplot.Data(downtime,ofunc,with_='lines',title=self.params.onsetmode)) | |
| 105 | + | |
| 106 | + # detected onsets | |
| 107 | + if not nplot: | |
| 108 | + for i in onsets: | |
| 109 | + x1.append(i[0]*self.params.step) | |
| 110 | + y1.append(self.maxofunc) | |
| 111 | + y1p.append(-self.maxofunc) | |
| 112 | + #x1 = array(onsets)*self.params.step | |
| 113 | + #y1 = self.maxofunc*ones(len(onsets)) | |
| 114 | + if x1: | |
| 115 | + oplot.append(Gnuplot.Data(x1,y1,with_='impulses')) | |
| 116 | + wplot.append(Gnuplot.Data(x1,y1p,with_='impulses')) | |
| 117 | + | |
| 118 | + oplots.append((oplot,self.params.onsetmode,self.maxofunc)) | |
| 119 | + | |
| 120 | + # check if ground truth datafile exists | |
| 121 | + datafile = self.input.replace('.wav','.txt') | |
| 122 | + if datafile == self.input: datafile = "" | |
| 123 | + if not os.path.isfile(datafile): | |
| 124 | + self.title = "" #"(no ground truth)" | |
| 125 | + else: | |
| 126 | + t_onsets = aubio.txtfile.read_datafile(datafile) | |
| 127 | + x2 = array(t_onsets).resize(len(t_onsets)) | |
| 128 | + y2 = self.maxofunc*ones(len(t_onsets)) | |
| 129 | + wplot.append(Gnuplot.Data(x2,y2,with_='impulses')) | |
| 130 | + | |
| 131 | + tol = 0.050 | |
| 132 | + | |
| 133 | + orig, missed, merged, expc, bad, doubled = \ | |
| 134 | + onset_roc(x2,x1,tol) | |
| 135 | + self.title = "GD %2.3f%% FP %2.3f%%" % \ | |
| 136 | + ((100*float(orig-missed-merged)/(orig)), | |
| 137 | + (100*float(bad+doubled)/(orig))) | |
| 138 | + | |
| 139 | + | |
| 140 | + def plotplot(self,wplot,oplots,outplot=None,extension=None,xsize=1.,ysize=1.,spectro=False): | |
| 141 | + from aubio.gnuplot import gnuplot_create, audio_to_array, make_audio_plot, audio_to_spec | |
| 142 | + import re | |
| 143 | + # prepare the plot | |
| 144 | + g = gnuplot_create(outplot=outplot, extension=extension) | |
| 145 | + g('set title \'%s\'' % (re.sub('.*/','',self.input))) | |
| 146 | + if spectro: | |
| 147 | + g('set size %f,%f' % (xsize,1.3*ysize) ) | |
| 148 | + else: | |
| 149 | + g('set size %f,%f' % (xsize,ysize) ) | |
| 150 | + g('set multiplot') | |
| 151 | + | |
| 152 | + # hack to align left axis | |
| 153 | + g('set lmargin 3') | |
| 154 | + g('set rmargin 6') | |
| 155 | + | |
| 156 | + if spectro: | |
| 157 | + import Gnuplot | |
| 158 | + minf = 50 | |
| 159 | + maxf = 500 | |
| 160 | + data,time,freq = audio_to_spec(self.input,minf=minf,maxf=maxf) | |
| 161 | + g('set size %f,%f' % (1.24*xsize , 0.34*ysize) ) | |
| 162 | + g('set origin %f,%f' % (-0.12,0.65*ysize)) | |
| 163 | + g('set xrange [0.:%f]' % time[-1]) | |
| 164 | + g('set yrange [%f:%f]' % (minf,maxf)) | |
| 165 | + g('set pm3d map') | |
| 166 | + g('unset colorbox') | |
| 167 | + g('set lmargin 0') | |
| 168 | + g('set rmargin 0') | |
| 169 | + g('set tmargin 0') | |
| 170 | + g('set palette rgbformulae -25,-24,-32') | |
| 171 | + g.xlabel('time (s)',offset=(0,1.)) | |
| 172 | + g.ylabel('freq (Hz)') | |
| 173 | + g('set origin 0,%f' % (1.0*ysize) ) | |
| 174 | + g('set format x "%1.1f"') | |
| 175 | + #if log: | |
| 176 | + # g('set yrange [%f:%f]' % (max(10,minf),maxf)) | |
| 177 | + # g('set log y') | |
| 178 | + g.splot(Gnuplot.GridData(data,time,freq, binary=1, title='')) | |
| 179 | + else: | |
| 180 | + # plot waveform and onsets | |
| 181 | + time,data = audio_to_array(self.input) | |
| 182 | + wplot = [make_audio_plot(time,data)] + wplot | |
| 183 | + g('set origin 0,%f' % (0.7*ysize) ) | |
| 184 | + g('set size %f,%f' % (xsize,0.3*ysize)) | |
| 185 | + g('set format y "%1f"') | |
| 186 | + g('set xrange [0:%f]' % max(time)) | |
| 187 | + g('set yrange [-1:1]') | |
| 188 | + g('set noytics') | |
| 189 | + g('set y2tics -1,1') | |
| 190 | + g.xlabel('time (s)',offset=(0,0.7)) | |
| 191 | + g.ylabel('amplitude') | |
| 192 | + g.plot(*wplot) | |
| 193 | + | |
| 194 | + # default settings for next plots | |
| 195 | + g('unset title') | |
| 196 | + g('set format x ""') | |
| 197 | + g('set format y "%3e"') | |
| 198 | + g('set tmargin 0') | |
| 199 | + g.xlabel('') | |
| 200 | + | |
| 201 | + N = len(oplots) | |
| 202 | + y = 0.7*ysize # the vertical proportion of the plot taken by onset functions | |
| 203 | + delta = 0.035 # the constant part of y taken by last plot label and data | |
| 204 | + for i in range(N): | |
| 205 | + # plot onset detection functions | |
| 206 | + g('set size %f,%f' % ( xsize, (y-delta)/N)) | |
| 207 | + g('set origin 0,%f' % ((N-i-1)*(y-delta)/N + delta )) | |
| 208 | + g('set nokey') | |
| 209 | + g('set xrange [0:%f]' % (self.lenofunc*self.params.step)) | |
| 210 | + g('set yrange [0:%f]' % (1.1*oplots[i][2])) | |
| 211 | + g('set y2tics ("0" 0, "%d" %d)' % (round(oplots[i][2]),round(oplots[i][2]))) | |
| 212 | + g.ylabel(oplots[i][1]) | |
| 213 | + if i == N-1: | |
| 214 | + g('set size %f,%f' % ( xsize, (y-delta)/N + delta ) ) | |
| 215 | + g('set origin 0,0') | |
| 216 | + g.xlabel('time (s)', offset=(0,0.7)) | |
| 217 | + g('set format x') | |
| 218 | + g.plot(*oplots[i][0]) | |
| 219 | + | |
| 220 | + g('unset multiplot') | |
| @@ -0,0 +1,33 @@ | ||
| 1 | + | |
| 2 | +class taskparams(object): | |
| 3 | + """ default parameters for task classes """ | |
| 4 | + def __init__(self,input=None,output=None): | |
| 5 | + self.silence = -90 | |
| 6 | + self.derivate = False | |
| 7 | + self.localmin = False | |
| 8 | + self.delay = 4. | |
| 9 | + self.storefunc = False | |
| 10 | + self.bufsize = 512 | |
| 11 | + self.hopsize = 256 | |
| 12 | + self.pbufsize = 2048 | |
| 13 | + self.phopsize = 512 | |
| 14 | + self.samplerate = 44100 | |
| 15 | + self.tol = 0.05 | |
| 16 | + self.mintol = 0.0 | |
| 17 | + self.step = float(self.hopsize)/float(self.samplerate) | |
| 18 | + self.threshold = 0.1 | |
| 19 | + self.onsetmode = 'dual' | |
| 20 | + self.pitchmode = 'yin' | |
| 21 | + # best threshold for yin monophonic Mirex04 (depth of f0) | |
| 22 | + self.yinthresh = 0.15 | |
| 23 | + # best thresh for yinfft monophonic Mirex04 (tradeoff sil/gd) | |
| 24 | + # also best param for yinfft polyphonic Mirex04 | |
| 25 | + self.yinfftthresh = 0.85 | |
| 26 | + self.pitchsmooth = 0 | |
| 27 | + self.pitchmin=20. | |
| 28 | + self.pitchmax=20000. | |
| 29 | + self.pitchdelay = -0.5 | |
| 30 | + self.dcthreshold = -1. | |
| 31 | + self.omode = "freq" | |
| 32 | + self.verbose = False | |
| 33 | + | |
| @@ -0,0 +1,234 @@ | ||
| 1 | +from aubio.task.task import task | |
| 2 | +from aubio.task.silence import tasksilence | |
| 3 | +from aubio.aubioclass import * | |
| 4 | + | |
| 5 | +class taskpitch(task): | |
| 6 | + def __init__(self,input,params=None): | |
| 7 | + task.__init__(self,input,params=params) | |
| 8 | + self.shortlist = [0. for i in range(self.params.pitchsmooth)] | |
| 9 | + if self.params.pitchmode == 'yin': | |
| 10 | + tolerance = self.params.yinthresh | |
| 11 | + elif self.params.pitchmode == 'yinfft': | |
| 12 | + tolerance = self.params.yinfftthresh | |
| 13 | + else: | |
| 14 | + tolerance = 0. | |
| 15 | + self.pitchdet = pitch(mode=self.params.pitchmode, | |
| 16 | + bufsize=self.params.bufsize, | |
| 17 | + hopsize=self.params.hopsize, | |
| 18 | + samplerate=self.srate, | |
| 19 | + omode=self.params.omode, | |
| 20 | + tolerance = tolerance) | |
| 21 | + | |
| 22 | + def __call__(self): | |
| 23 | + from aubio.median import short_find | |
| 24 | + task.__call__(self) | |
| 25 | + if (aubio_silence_detection(self.myvec(),self.params.silence)==1): | |
| 26 | + freq = -1. | |
| 27 | + else: | |
| 28 | + freq = self.pitchdet(self.myvec) | |
| 29 | + minpitch = self.params.pitchmin | |
| 30 | + maxpitch = self.params.pitchmax | |
| 31 | + if maxpitch and freq > maxpitch : | |
| 32 | + freq = -1. | |
| 33 | + elif minpitch and freq < minpitch : | |
| 34 | + freq = -1. | |
| 35 | + if self.params.pitchsmooth: | |
| 36 | + self.shortlist.append(freq) | |
| 37 | + self.shortlist.pop(0) | |
| 38 | + smoothfreq = short_find(self.shortlist, | |
| 39 | + len(self.shortlist)/2) | |
| 40 | + return smoothfreq | |
| 41 | + else: | |
| 42 | + return freq | |
| 43 | + | |
| 44 | + def compute_all(self): | |
| 45 | + """ Compute data """ | |
| 46 | + mylist = [] | |
| 47 | + while(self.readsize==self.params.hopsize): | |
| 48 | + freq = self() | |
| 49 | + mylist.append(freq) | |
| 50 | + if self.params.verbose: | |
| 51 | + self.fprint("%s\t%s" % (self.frameread*self.params.step,freq)) | |
| 52 | + return mylist | |
| 53 | + | |
| 54 | + def gettruth(self): | |
| 55 | + """ extract ground truth array in frequency """ | |
| 56 | + import os.path | |
| 57 | + """ from wavfile.txt """ | |
| 58 | + datafile = self.input.replace('.wav','.txt') | |
| 59 | + if datafile == self.input: datafile = "" | |
| 60 | + """ from file.<midinote>.wav """ | |
| 61 | + # FIXME very weak check | |
| 62 | + floatpit = self.input.split('.')[-2] | |
| 63 | + if not os.path.isfile(datafile) and len(self.input.split('.')) < 3: | |
| 64 | + print "no ground truth " | |
| 65 | + return False,False | |
| 66 | + elif floatpit: | |
| 67 | + try: | |
| 68 | + self.truth = float(floatpit) | |
| 69 | + #print "ground truth found in filename:", self.truth | |
| 70 | + tasksil = tasksilence(self.input,params=self.params) | |
| 71 | + time,pitch =[],[] | |
| 72 | + while(tasksil.readsize==tasksil.params.hopsize): | |
| 73 | + tasksil() | |
| 74 | + time.append(tasksil.params.step*(tasksil.frameread)) | |
| 75 | + if not tasksil.issilence: | |
| 76 | + pitch.append(self.truth) | |
| 77 | + else: | |
| 78 | + pitch.append(-1.) | |
| 79 | + return time,pitch | |
| 80 | + except ValueError: | |
| 81 | + # FIXME very weak check | |
| 82 | + if not os.path.isfile(datafile): | |
| 83 | + print "no ground truth found" | |
| 84 | + return 0,0 | |
| 85 | + else: | |
| 86 | + from aubio.txtfile import read_datafile | |
| 87 | + values = read_datafile(datafile) | |
| 88 | + time, pitch = [], [] | |
| 89 | + for i in range(len(values)): | |
| 90 | + time.append(values[i][0]) | |
| 91 | + if values[i][1] == 0.0: | |
| 92 | + pitch.append(-1.) | |
| 93 | + else: | |
| 94 | + pitch.append(aubio_freqtomidi(values[i][1])) | |
| 95 | + return time,pitch | |
| 96 | + | |
| 97 | + def oldeval(self,results): | |
| 98 | + def mmean(l): | |
| 99 | + return sum(l)/max(float(len(l)),1) | |
| 100 | + | |
| 101 | + from aubio.median import percental | |
| 102 | + timet,pitcht = self.gettruth() | |
| 103 | + res = [] | |
| 104 | + for i in results: | |
| 105 | + #print i,self.truth | |
| 106 | + if i <= 0: pass | |
| 107 | + else: res.append(self.truth-i) | |
| 108 | + if not res or len(res) < 3: | |
| 109 | + avg = self.truth; med = self.truth | |
| 110 | + else: | |
| 111 | + avg = mmean(res) | |
| 112 | + med = percental(res,len(res)/2) | |
| 113 | + return self.truth, self.truth-med, self.truth-avg | |
| 114 | + | |
| 115 | + def eval(self,pitch,tol=0.5): | |
| 116 | + timet,pitcht = self.gettruth() | |
| 117 | + pitch = [aubio_freqtomidi(i) for i in pitch] | |
| 118 | + for i in range(len(pitch)): | |
| 119 | + if pitch[i] == "nan" or pitch[i] == -1: | |
| 120 | + pitch[i] = -1 | |
| 121 | + time = [ (i+self.params.pitchdelay)*self.params.step for i in range(len(pitch)) ] | |
| 122 | + #print len(timet),len(pitcht) | |
| 123 | + #print len(time),len(pitch) | |
| 124 | + if len(timet) != len(time): | |
| 125 | + time = time[1:len(timet)+1] | |
| 126 | + pitch = pitch[1:len(pitcht)+1] | |
| 127 | + #pitcht = [aubio_freqtomidi(i) for i in pitcht] | |
| 128 | + for i in range(len(pitcht)): | |
| 129 | + if pitcht[i] == "nan" or pitcht[i] == "-inf" or pitcht[i] == -1: | |
| 130 | + pitcht[i] = -1 | |
| 131 | + assert len(timet) == len(time) | |
| 132 | + assert len(pitcht) == len(pitch) | |
| 133 | + osil, esil, opit, epit, echr = 0, 0, 0, 0, 0 | |
| 134 | + for i in range(len(pitcht)): | |
| 135 | + if pitcht[i] == -1: # currently silent | |
| 136 | + osil += 1 # count a silence | |
| 137 | + if pitch[i] <= 0. or pitch[i] == "nan": | |
| 138 | + esil += 1 # found a silence | |
| 139 | + else: | |
| 140 | + opit +=1 | |
| 141 | + if abs(pitcht[i] - pitch[i]) < tol: | |
| 142 | + epit += 1 | |
| 143 | + echr += 1 | |
| 144 | + elif abs(pitcht[i] - pitch[i]) % 12. < tol: | |
| 145 | + echr += 1 | |
| 146 | + #else: | |
| 147 | + # print timet[i], pitcht[i], time[i], pitch[i] | |
| 148 | + #print "origsilence", "foundsilence", "origpitch", "foundpitch", "orig pitchroma", "found pitchchroma" | |
| 149 | + #print 100.*esil/float(osil), 100.*epit/float(opit), 100.*echr/float(opit) | |
| 150 | + return osil, esil, opit, epit, echr | |
| 151 | + | |
| 152 | + def plot(self,pitch,wplot,oplots,titles,outplot=None): | |
| 153 | + import Gnuplot | |
| 154 | + | |
| 155 | + time = [ (i+self.params.pitchdelay)*self.params.step for i in range(len(pitch)) ] | |
| 156 | + pitch = [aubio_freqtomidi(i) for i in pitch] | |
| 157 | + oplots.append(Gnuplot.Data(time,pitch,with_='lines', | |
| 158 | + title=self.params.pitchmode)) | |
| 159 | + titles.append(self.params.pitchmode) | |
| 160 | + | |
| 161 | + | |
| 162 | + def plotplot(self,wplot,oplots,titles,outplot=None,extension=None,xsize=1.,ysize=1.,multiplot = 1, midi = 1, truth = 1): | |
| 163 | + from aubio.gnuplot import gnuplot_create , audio_to_array, make_audio_plot | |
| 164 | + import re | |
| 165 | + import Gnuplot | |
| 166 | + | |
| 167 | + # check if ground truth exists | |
| 168 | + if truth: | |
| 169 | + timet,pitcht = self.gettruth() | |
| 170 | + if timet and pitcht: | |
| 171 | + oplots = [Gnuplot.Data(timet,pitcht,with_='lines', | |
| 172 | + title='ground truth')] + oplots | |
| 173 | + | |
| 174 | + g = gnuplot_create(outplot=outplot, extension=extension) | |
| 175 | + g('set title \'%s\'' % (re.sub('.*/','',self.input))) | |
| 176 | + g('set size %f,%f' % (xsize,ysize) ) | |
| 177 | + g('set multiplot') | |
| 178 | + # hack to align left axis | |
| 179 | + g('set lmargin 4') | |
| 180 | + g('set rmargin 4') | |
| 181 | + # plot waveform | |
| 182 | + time,data = audio_to_array(self.input) | |
| 183 | + wplot = [make_audio_plot(time,data)] | |
| 184 | + g('set origin 0,%f' % (0.7*ysize) ) | |
| 185 | + g('set size %f,%f' % (xsize,0.3*ysize)) | |
| 186 | + #g('set format y "%1f"') | |
| 187 | + g('set xrange [0:%f]' % max(time)) | |
| 188 | + g('set yrange [-1:1]') | |
| 189 | + g('set noytics') | |
| 190 | + g('set y2tics -1,1') | |
| 191 | + g.xlabel('time (s)',offset=(0,0.7)) | |
| 192 | + g.ylabel('amplitude') | |
| 193 | + g.plot(*wplot) | |
| 194 | + | |
| 195 | + # default settings for next plots | |
| 196 | + g('unset title') | |
| 197 | + g('set format x ""') | |
| 198 | + g('set format y "%3e"') | |
| 199 | + g('set tmargin 0') | |
| 200 | + g.xlabel('') | |
| 201 | + g('set noclip one') | |
| 202 | + | |
| 203 | + if not midi: | |
| 204 | + g('set log y') | |
| 205 | + #g.xlabel('time (s)') | |
| 206 | + g.ylabel('f0 (Hz)') | |
| 207 | + g('set yrange [100:%f]' % self.params.pitchmax) | |
| 208 | + else: | |
| 209 | + g.ylabel('midi') | |
| 210 | + g('set yrange [%f:%f]' % (aubio_freqtomidi(self.params.pitchmin), aubio_freqtomidi(self.params.pitchmax))) | |
| 211 | + g('set y2tics %f,%f' % (round(aubio_freqtomidi(self.params.pitchmin)+.5),12)) | |
| 212 | + | |
| 213 | + if multiplot: | |
| 214 | + N = len(oplots) | |
| 215 | + y = 0.7*ysize # the vertical proportion of the plot taken by onset functions | |
| 216 | + delta = 0.035 # the constant part of y taken by last plot label and data | |
| 217 | + for i in range(N): | |
| 218 | + # plot pitch detection functions | |
| 219 | + g('set size %f,%f' % ( xsize, (y-delta)/N)) | |
| 220 | + g('set origin 0,%f' % ((N-i-1)*(y-delta)/N + delta )) | |
| 221 | + g('set nokey') | |
| 222 | + g('set xrange [0:%f]' % max(time)) | |
| 223 | + g.ylabel(titles[i]) | |
| 224 | + if i == N-1: | |
| 225 | + g('set size %f,%f' % (xsize, (y-delta)/N + delta ) ) | |
| 226 | + g('set origin 0,0') | |
| 227 | + g.xlabel('time (s)', offset=(0,0.7)) | |
| 228 | + g('set format x') | |
| 229 | + g.plot(oplots[i]) | |
| 230 | + else: | |
| 231 | + g('set key right top') | |
| 232 | + g.plot(*oplots) | |
| 233 | + g('unset multiplot') | |
| 234 | + | |
| @@ -0,0 +1,28 @@ | ||
| 1 | +from aubio.task.task import task | |
| 2 | +from aubio.aubioclass import * | |
| 3 | + | |
| 4 | +class tasksilence(task): | |
| 5 | + wassilence = 1 | |
| 6 | + issilence = 1 | |
| 7 | + def __call__(self): | |
| 8 | + task.__call__(self) | |
| 9 | + if (aubio_silence_detection(self.myvec(),self.params.silence)==1): | |
| 10 | + if self.wassilence == 1: self.issilence = 1 | |
| 11 | + else: self.issilence = 2 | |
| 12 | + self.wassilence = 1 | |
| 13 | + else: | |
| 14 | + if self.wassilence <= 0: self.issilence = 0 | |
| 15 | + else: self.issilence = -1 | |
| 16 | + self.wassilence = 0 | |
| 17 | + if self.issilence == -1: | |
| 18 | + return max(self.frameread-self.params.delay,0.), -1 | |
| 19 | + elif self.issilence == 2: | |
| 20 | + return max(self.frameread+self.params.delay,0.), 2 | |
| 21 | + | |
| 22 | + def fprint(self,foo): | |
| 23 | + print self.params.step*foo[0], | |
| 24 | + if foo[1] == 2: print "OFF" | |
| 25 | + else: print "ON" | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| @@ -0,0 +1,53 @@ | ||
| 1 | +from aubio.aubioclass import * | |
| 2 | +from params import taskparams | |
| 3 | + | |
| 4 | +class task(taskparams): | |
| 5 | + """ default template class to apply tasks on a stream """ | |
| 6 | + def __init__(self,input,output=None,params=None): | |
| 7 | + """ open the input file and initialize default argument | |
| 8 | + parameters should be set *before* calling this method. | |
| 9 | + """ | |
| 10 | + import time | |
| 11 | + self.tic = time.time() | |
| 12 | + if params == None: self.params = taskparams() | |
| 13 | + else: self.params = params | |
| 14 | + self.frameread = 0 | |
| 15 | + self.readsize = self.params.hopsize | |
| 16 | + self.input = input | |
| 17 | + self.filei = sndfile(self.input) | |
| 18 | + self.srate = self.filei.samplerate() | |
| 19 | + self.params.step = float(self.params.hopsize)/float(self.srate) | |
| 20 | + self.myvec = fvec(self.params.hopsize) | |
| 21 | + self.output = output | |
| 22 | + | |
| 23 | + def __call__(self): | |
| 24 | + self.readsize = self.filei.read(self.params.hopsize,self.myvec) | |
| 25 | + self.frameread += 1 | |
| 26 | + | |
| 27 | + def compute_all(self): | |
| 28 | + """ Compute data """ | |
| 29 | + mylist = [] | |
| 30 | + while(self.readsize==self.params.hopsize): | |
| 31 | + tmp = self() | |
| 32 | + if tmp: | |
| 33 | + mylist.append(tmp) | |
| 34 | + if self.params.verbose: | |
| 35 | + self.fprint(tmp) | |
| 36 | + return mylist | |
| 37 | + | |
| 38 | + def fprint(self,foo): | |
| 39 | + print foo | |
| 40 | + | |
| 41 | + def eval(self,results): | |
| 42 | + """ Eval data """ | |
| 43 | + pass | |
| 44 | + | |
| 45 | + def plot(self): | |
| 46 | + """ Plot data """ | |
| 47 | + pass | |
| 48 | + | |
| 49 | + def time(self): | |
| 50 | + import time | |
| 51 | + #print "CPU time is now %f seconds," % time.clock(), | |
| 52 | + #print "task execution took %f seconds" % (time.time() - self.tic) | |
| 53 | + return time.time() - self.tic | |
| @@ -0,0 +1,47 @@ | ||
| 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-2009 Paul Brossier <piem@aubio.org> | |
| 7 | + | |
| 8 | + This file is part of aubio. | |
| 9 | + | |
| 10 | + aubio is free software: you can redistribute it and/or modify | |
| 11 | + it under the terms of the GNU General Public License as published by | |
| 12 | + the Free Software Foundation, either version 3 of the License, or | |
| 13 | + (at your option) any later version. | |
| 14 | + | |
| 15 | + aubio is distributed in the hope that it will be useful, | |
| 16 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 17 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 18 | + GNU General Public License for more details. | |
| 19 | + | |
| 20 | + You should have received a copy of the GNU General Public License | |
| 21 | + along with aubio. If not, see <http://www.gnu.org/licenses/>. | |
| 22 | +""" | |
| 23 | + | |
| 24 | +def read_datafile(filename,depth=-1): | |
| 25 | + """read list data from a text file (columns of float)""" | |
| 26 | + if filename == '--' or filename == '-': | |
| 27 | + import sys | |
| 28 | + fres = sys.stdin | |
| 29 | + else: | |
| 30 | + fres = open(filename,'ro') | |
| 31 | + l = [] | |
| 32 | + while 1: | |
| 33 | + tmp = fres.readline() | |
| 34 | + if not tmp : break | |
| 35 | + else: tmp = tmp.split() | |
| 36 | + if depth > 0: | |
| 37 | + for i in range(min(depth,len(tmp))): | |
| 38 | + tmp[i] = float(tmp[i]) | |
| 39 | + l.append(tmp) | |
| 40 | + elif depth == 0: | |
| 41 | + l.append(float(tmp[0])) | |
| 42 | + else: | |
| 43 | + for i in range(len(tmp)): | |
| 44 | + tmp[i] = float(tmp[i]) | |
| 45 | + l.append(tmp) | |
| 46 | + return l | |
| 47 | + | |
Empty file added.
| @@ -0,0 +1,167 @@ | ||
| 1 | + # | |
| 2 | + # Copyright 2004 Apache Software Foundation | |
| 3 | + # | |
| 4 | + # Licensed under the Apache License, Version 2.0 (the "License"); you | |
| 5 | + # may not use this file except in compliance with the License. You | |
| 6 | + # may obtain a copy of the License at | |
| 7 | + # | |
| 8 | + # http://www.apache.org/licenses/LICENSE-2.0 | |
| 9 | + # | |
| 10 | + # Unless required by applicable law or agreed to in writing, software | |
| 11 | + # distributed under the License is distributed on an "AS IS" BASIS, | |
| 12 | + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |
| 13 | + # implied. See the License for the specific language governing | |
| 14 | + # permissions and limitations under the License. | |
| 15 | + # | |
| 16 | + # Originally developed by Gregory Trubetskoy. | |
| 17 | + # | |
| 18 | + # $Id: publisher.py,v 1.36 2004/02/16 19:47:27 grisha Exp $ | |
| 19 | + | |
| 20 | +""" | |
| 21 | + This handler is conceputally similar to Zope's ZPublisher, except | |
| 22 | + that it: | |
| 23 | + | |
| 24 | + 1. Is written specifically for mod_python and is therefore much faster | |
| 25 | + 2. Does not require objects to have a documentation string | |
| 26 | + 3. Passes all arguments as simply string | |
| 27 | + 4. Does not try to match Python errors to HTTP errors | |
| 28 | + 5. Does not give special meaning to '.' and '..'. | |
| 29 | + | |
| 30 | + This is a modified version of mod_python.publisher.handler Only the first | |
| 31 | + directory argument is matched, the rest is left for path_info. A default | |
| 32 | + one must be provided. | |
| 33 | + | |
| 34 | +""" | |
| 35 | + | |
| 36 | +from mod_python import apache | |
| 37 | +from mod_python import util | |
| 38 | +from mod_python.publisher import resolve_object,process_auth,imp_suffixes | |
| 39 | + | |
| 40 | +import sys | |
| 41 | +import os | |
| 42 | +import re | |
| 43 | + | |
| 44 | +from types import * | |
| 45 | + | |
| 46 | +def configure_handler(req,default): | |
| 47 | + | |
| 48 | + req.allow_methods(["GET", "POST"]) | |
| 49 | + if req.method not in ["GET", "POST"]: | |
| 50 | + raise apache.SERVER_RETURN, apache.HTTP_METHOD_NOT_ALLOWED | |
| 51 | + | |
| 52 | + func_path = "" | |
| 53 | + if req.path_info: | |
| 54 | + func_path = req.path_info[1:] # skip first / | |
| 55 | + #func_path = func_path.replace("/", ".") | |
| 56 | + #if func_path[-1:] == ".": | |
| 57 | + # func_path = func_path[:-1] | |
| 58 | + # changed: only keep the first directory | |
| 59 | + func_path = re.sub('/.*','',func_path) | |
| 60 | + | |
| 61 | + # default to 'index' if no path_info was given | |
| 62 | + if not func_path: | |
| 63 | + func_path = "index" | |
| 64 | + | |
| 65 | + # if any part of the path begins with "_", abort | |
| 66 | + if func_path[0] == '_' or func_path.count("._"): | |
| 67 | + raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND | |
| 68 | + | |
| 69 | + ## import the script | |
| 70 | + path, module_name = os.path.split(req.filename) | |
| 71 | + if not module_name: | |
| 72 | + module_name = "index" | |
| 73 | + | |
| 74 | + # get rid of the suffix | |
| 75 | + # explanation: Suffixes that will get stripped off | |
| 76 | + # are those that were specified as an argument to the | |
| 77 | + # AddHandler directive. Everything else will be considered | |
| 78 | + # a package.module rather than module.suffix | |
| 79 | + exts = req.get_addhandler_exts() | |
| 80 | + if not exts: | |
| 81 | + # this is SetHandler, make an exception for Python suffixes | |
| 82 | + exts = imp_suffixes | |
| 83 | + if req.extension: # this exists if we're running in a | .ext handler | |
| 84 | + exts += req.extension[1:] | |
| 85 | + if exts: | |
| 86 | + suffixes = exts.strip().split() | |
| 87 | + exp = "\\." + "$|\\.".join(suffixes) | |
| 88 | + suff_matcher = re.compile(exp) # python caches these, so its fast | |
| 89 | + module_name = suff_matcher.sub("", module_name) | |
| 90 | + | |
| 91 | + # import module (or reload if needed) | |
| 92 | + # the [path] argument tells import_module not to allow modules whose | |
| 93 | + # full path is not in [path] or below. | |
| 94 | + config = req.get_config() | |
| 95 | + autoreload=int(config.get("PythonAutoReload", 1)) | |
| 96 | + log=int(config.get("PythonDebug", 0)) | |
| 97 | + try: | |
| 98 | + module = apache.import_module(module_name, | |
| 99 | + autoreload=autoreload, | |
| 100 | + log=log, | |
| 101 | + path=[path]) | |
| 102 | + except ImportError: | |
| 103 | + et, ev, etb = sys.exc_info() | |
| 104 | + # try again, using default module, perhaps this is a | |
| 105 | + # /directory/function (as opposed to /directory/module/function) | |
| 106 | + func_path = module_name | |
| 107 | + module_name = "index" | |
| 108 | + try: | |
| 109 | + module = apache.import_module(module_name, | |
| 110 | + autoreload=autoreload, | |
| 111 | + log=log, | |
| 112 | + path=[path]) | |
| 113 | + except ImportError: | |
| 114 | + # raise the original exception | |
| 115 | + raise et, ev, etb | |
| 116 | + | |
| 117 | + # does it have an __auth__? | |
| 118 | + realm, user, passwd = process_auth(req, module) | |
| 119 | + | |
| 120 | + # resolve the object ('traverse') | |
| 121 | + try: | |
| 122 | + object = resolve_object(req, module, func_path, realm, user, passwd) | |
| 123 | + except AttributeError: | |
| 124 | + # changed, return the default path instead | |
| 125 | + #raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND | |
| 126 | + object = default | |
| 127 | + # not callable, a class or an unbound method | |
| 128 | + if (not callable(object) or | |
| 129 | + type(object) is ClassType or | |
| 130 | + (hasattr(object, 'im_self') and not object.im_self)): | |
| 131 | + | |
| 132 | + result = str(object) | |
| 133 | + | |
| 134 | + else: | |
| 135 | + # callable, (but not a class or unbound method) | |
| 136 | + | |
| 137 | + # process input, if any | |
| 138 | + req.form = util.FieldStorage(req, keep_blank_values=1) | |
| 139 | + | |
| 140 | + result = util.apply_fs_data(object, req.form, req=req) | |
| 141 | + | |
| 142 | + if result or req.bytes_sent > 0 or req.next: | |
| 143 | + | |
| 144 | + if result is None: | |
| 145 | + result = "" | |
| 146 | + else: | |
| 147 | + result = str(result) | |
| 148 | + | |
| 149 | + # unless content_type was manually set, we will attempt | |
| 150 | + # to guess it | |
| 151 | + if not req._content_type_set: | |
| 152 | + # make an attempt to guess content-type | |
| 153 | + if result[:100].strip()[:6].lower() == '<html>' \ | |
| 154 | + or result.find('</') > 0: | |
| 155 | + req.content_type = 'text/html' | |
| 156 | + else: | |
| 157 | + req.content_type = 'text/plain' | |
| 158 | + | |
| 159 | + if req.method != "HEAD": | |
| 160 | + req.write(result) | |
| 161 | + else: | |
| 162 | + req.write("") | |
| 163 | + return apache.OK | |
| 164 | + else: | |
| 165 | + req.log_error("mod_python.publisher: %s returned nothing." % `object`) | |
| 166 | + return apache.HTTP_INTERNAL_SERVER_ERROR | |
| 167 | + | |
| @@ -0,0 +1,286 @@ | ||
| 1 | +from aubio.bench.node import * | |
| 2 | + | |
| 3 | +def parse_args(req): | |
| 4 | + req.basehref = BASEHREF | |
| 5 | + req.datadir = DATADIR | |
| 6 | + if req.path_info: path_info = req.path_info | |
| 7 | + else: path_info = '/' | |
| 8 | + location = re.sub('^/show_[a-z0-9]*/','',path_info) | |
| 9 | + location = re.sub('^/play_[a-z0-9]*/','',location) | |
| 10 | + location = re.sub('^/index/','',location) | |
| 11 | + location = re.sub('^/','',location) | |
| 12 | + location = re.sub('/$','',location) | |
| 13 | + datapath = "%s/%s" % (DATADIR,location) | |
| 14 | + respath = "%s/%s" % (DATADIR,location) | |
| 15 | + last = re.sub('/$','',location) | |
| 16 | + last = last.split('/')[-1] | |
| 17 | + first = path_info.split('/')[1] | |
| 18 | + # store some of this in the mp_request | |
| 19 | + req.location, req.datapath, req.respath = location, datapath, respath | |
| 20 | + req.first, req.last = first, last | |
| 21 | + | |
| 22 | + if location: | |
| 23 | + if not (os.path.isfile(datapath) or | |
| 24 | + os.path.isdir(datapath) or | |
| 25 | + location in ['feedback','email']): | |
| 26 | + # the path was not understood | |
| 27 | + from mod_python import apache | |
| 28 | + req.write("<html> path not found %s</html>" % (datapath)) | |
| 29 | + raise apache.SERVER_RETURN, apache.OK | |
| 30 | + #from mod_python import apache | |
| 31 | + #raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND | |
| 32 | + | |
| 33 | +def navigation(req): | |
| 34 | + """ main html navigation header """ | |
| 35 | + from mod_python import psp | |
| 36 | + req.content_type = "text/html" | |
| 37 | + parse_args(req) | |
| 38 | + datapath = req.datapath | |
| 39 | + location = req.location | |
| 40 | + | |
| 41 | + # deal with session | |
| 42 | + if req.sess.is_new(): | |
| 43 | + msg = "<b>Welcome %s</b><br>" % req.sess['login'] | |
| 44 | + else: | |
| 45 | + msg = "<b>Welcome back %s</b><br>" % req.sess['login'] | |
| 46 | + | |
| 47 | + # start writing | |
| 48 | + tmpl = psp.PSP(req, filename='header.tmpl') | |
| 49 | + tmpl.run(vars = { 'title': "aubioweb / %s / %s" % (req.first,location), | |
| 50 | + 'basehref': '/~piem/', | |
| 51 | + 'message': msg, | |
| 52 | + 'action': req.first}) | |
| 53 | + | |
| 54 | + req.write("<h2>Content of ") | |
| 55 | + print_link(req,"","/") | |
| 56 | + y = location.split('/') | |
| 57 | + for i in range(len(y)-1): | |
| 58 | + print_link(req,"/".join(y[:i+1]),y[i]) | |
| 59 | + req.write(" / ") | |
| 60 | + req.write("%s</h2>\n" % y[-1]) | |
| 61 | + | |
| 62 | + a = {'show_info' : 'info', | |
| 63 | + 'show_sound': 'waveform', | |
| 64 | + 'show_onset': 'onset', | |
| 65 | + 'index' : 'index', | |
| 66 | + 'show_pitch': 'pitch', | |
| 67 | + 'play_m3u': 'stream (m3u/ogg)', | |
| 68 | + 'play_ogg': 'save (ogg)', | |
| 69 | + 'play_wav': 'save (wav)', | |
| 70 | + } | |
| 71 | + | |
| 72 | + # print task lists (only remaining tasks) | |
| 73 | + print_link(req,re.sub('%s.*'%req.last,'',location),"go up") | |
| 74 | + akeys = a.keys(); akeys.sort(); | |
| 75 | + curkey = req.first | |
| 76 | + for akey in akeys: | |
| 77 | + if akey != curkey: | |
| 78 | + req.write(":: ") | |
| 79 | + print_link(req,"/".join((akey,location)),a[akey]) | |
| 80 | + else: | |
| 81 | + req.write(":: ") | |
| 82 | + req.write("<b>%s</b>" % a[akey]) | |
| 83 | + req.write("<br>") | |
| 84 | + | |
| 85 | + # list the content of the directories | |
| 86 | + listdir,listfiles = [],[] | |
| 87 | + if os.path.isdir(datapath): | |
| 88 | + listfiles = list_snd_files(datapath) | |
| 89 | + listdir = list_dirs(datapath) | |
| 90 | + listdir.pop(0) # kick the current dir | |
| 91 | + elif os.path.isfile(datapath): | |
| 92 | + listfiles = [datapath] | |
| 93 | + listdir = [re.sub(req.last,'',location)] | |
| 94 | + | |
| 95 | + link_list(req,listdir,title="Subdirectories") | |
| 96 | + link_list(req,listfiles,title="Files") | |
| 97 | + | |
| 98 | +def footer(req): | |
| 99 | + """ html navigation footer """ | |
| 100 | + from mod_python import psp | |
| 101 | + tmpl = psp.PSP(req, filename='footer.tmpl') | |
| 102 | + tmpl.run(vars = { 'time': -req.mtime+req.request_time }) | |
| 103 | + | |
| 104 | +def apply_on_data(req, func,**keywords): | |
| 105 | + # bug: hardcoded snd file filter | |
| 106 | + act_on_data(func,req.datapath,req.respath, | |
| 107 | + filter="f -maxdepth 1 -name '*.wav' -o -name '*.aif'",**keywords) | |
| 108 | + | |
| 109 | +def print_link(req,target,name,basehref=BASEHREF): | |
| 110 | + req.write("<a href='%s/%s'>%s</a>\n" % (basehref,target,name)) | |
| 111 | + | |
| 112 | +def print_img(req,target,name='',basehref=BASEHREF): | |
| 113 | + if name == '': name = target | |
| 114 | + req.write("<img src='%s/%s' alt='%s' title='%s'>\n" % (basehref,target,name,name)) | |
| 115 | + | |
| 116 | +def link_list(req,targetlist,basehref=BASEHREF,title=None): | |
| 117 | + if len(targetlist) > 1: | |
| 118 | + if title: req.write("<h3>%s</h3>"%title) | |
| 119 | + req.write('<ul>') | |
| 120 | + for i in targetlist: | |
| 121 | + s = re.split('%s/'%DATADIR,i,maxsplit=1)[1] | |
| 122 | + if s: | |
| 123 | + req.write('<li>') | |
| 124 | + print_link(req,s,s) | |
| 125 | + req.write('</li>') | |
| 126 | + req.write('</ul>') | |
| 127 | + | |
| 128 | +def print_list(req,list): | |
| 129 | + req.write("<pre>\n") | |
| 130 | + for i in list: req.write("%s\n" % i) | |
| 131 | + req.write("</pre>\n") | |
| 132 | + | |
| 133 | +def print_command(req,command): | |
| 134 | + req.write("<h4>%s</h4>\n" % re.sub('%%','%',command)) | |
| 135 | + def print_runcommand(input,output): | |
| 136 | + cmd = re.sub('(%)?%i','%s' % input, command) | |
| 137 | + cmd = re.sub('(%)?%o','%s' % output, cmd) | |
| 138 | + print_list(req,runcommand(cmd)) | |
| 139 | + apply_on_data(req,print_runcommand) | |
| 140 | + | |
| 141 | +def datapath_to_location(input): | |
| 142 | + location = re.sub(DATADIR,'',input) | |
| 143 | + return re.sub('^/*','',location) | |
| 144 | + | |
| 145 | +## drawing hacks | |
| 146 | +def draw_func(req,func): | |
| 147 | + import re | |
| 148 | + req.content_type = "image/png" | |
| 149 | + # build location (strip the func_path, add DATADIR) | |
| 150 | + location = re.sub('^/draw_[a-z]*/','%s/'%DATADIR,req.path_info) | |
| 151 | + location = re.sub('.png$','',location) | |
| 152 | + if not os.path.isfile(location): | |
| 153 | + from mod_python import apache | |
| 154 | + raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND | |
| 155 | + # replace location in func | |
| 156 | + cmd = re.sub('(%)?%i','%s' % location, func) | |
| 157 | + # add PYTHONPATH at the beginning, | |
| 158 | + cmd = "%s%s 2> /dev/null" % (PYTHONPATH,cmd) | |
| 159 | + for each in runcommand(cmd): | |
| 160 | + req.write("%s\n"%each) | |
| 161 | + | |
| 162 | +def show_task(req,task): | |
| 163 | + def show_task_file(input,output,task): | |
| 164 | + location = datapath_to_location(input) | |
| 165 | + print_img(req,"draw_%s/%s" % (task,location)) | |
| 166 | + navigation(req) | |
| 167 | + req.write("<h3>%s</h3>\n" % task) | |
| 168 | + apply_on_data(req,show_task_file,task=task) | |
| 169 | + footer(req) | |
| 170 | + | |
| 171 | +## waveform_foo | |
| 172 | +def draw_sound(req): | |
| 173 | + draw_func(req,"aubioplot-audio %%i stdout 2> /dev/null") | |
| 174 | + | |
| 175 | +def show_sound(req): | |
| 176 | + show_task(req,"sound") | |
| 177 | + | |
| 178 | +## pitch foo | |
| 179 | +def draw_pitch(req,threshold='0.3'): | |
| 180 | + draw_func(req,"aubiopitch -i %%i -p -m schmitt,yin,fcomb,mcomb -t %s -O stdout" % threshold) | |
| 181 | + | |
| 182 | +def show_pitch(req): | |
| 183 | + show_task(req,"pitch") | |
| 184 | + | |
| 185 | +## onset foo | |
| 186 | +def draw_onset(req,threshold='0.3'): | |
| 187 | + draw_func(req,"aubiocut -i %%i -p -m complex -t %s -O stdout" % threshold) | |
| 188 | + | |
| 189 | +def show_onset(req,threshold='0.3',details=''): | |
| 190 | + def onset_file(input,output): | |
| 191 | + location = datapath_to_location(input) | |
| 192 | + print_img(req,"draw_onset/%s?threshold=%s"%(location,threshold)) | |
| 193 | + print_link(req,"?threshold=%s" % (float(threshold)-0.1),"-") | |
| 194 | + req.write("%s\n" % threshold) | |
| 195 | + print_link(req,"?threshold=%s" % (float(threshold)+0.1),"+") | |
| 196 | + # bug: hardcoded sndfile extension | |
| 197 | + anote = re.sub('\.wav$','.txt',input) | |
| 198 | + if anote == input: anote = "" | |
| 199 | + res = get_extract(input,threshold) | |
| 200 | + if os.path.isfile(anote): | |
| 201 | + tru = get_anote(anote) | |
| 202 | + print_list(req,get_results(tru,res,0.05)) | |
| 203 | + else: | |
| 204 | + req.write("no ground truth found<br>\n") | |
| 205 | + if details: | |
| 206 | + req.write("<h4>Extraction</h4>\n") | |
| 207 | + print_list(req,res) | |
| 208 | + else: | |
| 209 | + req.write("<a href='%s/show_onset/%s?details=yes&threshold=%s'>details</a><br>\n" % | |
| 210 | + (req.basehref,location,threshold)) | |
| 211 | + if details and os.path.isfile(anote): | |
| 212 | + req.write("<h4>Computed differences</h4>\n") | |
| 213 | + ldiffs = get_diffs(tru,res,0.05) | |
| 214 | + print_list(req,ldiffs) | |
| 215 | + req.write("<h4>Annotations</h4>\n") | |
| 216 | + print_list(req,tru) | |
| 217 | + navigation(req) | |
| 218 | + req.write("<h3>Onset</h3>\n") | |
| 219 | + apply_on_data(req,onset_file) | |
| 220 | + footer(req) | |
| 221 | + | |
| 222 | +def get_anote(anote): | |
| 223 | + import aubio.onsetcompare | |
| 224 | + # FIXME: should import with txtfile.read_datafile | |
| 225 | + return aubio.onsetcompare.load_onsets(anote) | |
| 226 | + | |
| 227 | +def get_diffs(anote,extract,tol): | |
| 228 | + import aubio.onsetcompare | |
| 229 | + return aubio.onsetcompare.onset_diffs(anote,extract,tol) | |
| 230 | + | |
| 231 | +def get_extract(datapath,threshold='0.3'): | |
| 232 | + cmd = "%saubiocut -v -m complex -t %s -i %s" % (PYTHONPATH,threshold,datapath) | |
| 233 | + lo = runcommand(cmd) | |
| 234 | + for i in range(len(lo)): lo[i] = float(lo[i]) | |
| 235 | + return lo | |
| 236 | + | |
| 237 | +def get_results(anote,extract,tol): | |
| 238 | + import aubio.onsetcompare | |
| 239 | + orig, missed, merged, expc, bad, doubled = aubio.onsetcompare.onset_roc(anote,extract,tol) | |
| 240 | + s =("GD %2.8f\t" % (100*float(orig-missed-merged)/(orig)), | |
| 241 | + "FP %2.8f\t" % (100*float(bad+doubled)/(orig)) , | |
| 242 | + "GD-merged %2.8f\t" % (100*float(orig-missed)/(orig)) , | |
| 243 | + "FP-pruned %2.8f\t" % (100*float(bad)/(orig)) ) | |
| 244 | + return s | |
| 245 | + | |
| 246 | +# play m3u foo | |
| 247 | +def play_m3u(req): | |
| 248 | + def show_task_file(input,output,task): | |
| 249 | + location = datapath_to_location(input) | |
| 250 | + req.write("http://%s%s/play_ogg/%s\n" % (HOSTNAME,BASEHREF,re.sub("play_m3u",task,location))) | |
| 251 | + req.content_type = "audio/mpegurl" | |
| 252 | + parse_args(req) | |
| 253 | + apply_on_data(req,show_task_file,task="play_ogg") | |
| 254 | + | |
| 255 | +# play wav foo | |
| 256 | +def play_wav(req): | |
| 257 | + req.content_type = "audio/x-wav" | |
| 258 | + func = "cat %%i" | |
| 259 | + # build location (strip the func_path, add DATADIR) | |
| 260 | + location = re.sub('^/play_wav/','%s/'%DATADIR,req.path_info) | |
| 261 | + if not os.path.isfile(location): | |
| 262 | + from mod_python import apache | |
| 263 | + raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND | |
| 264 | + # replace location in func | |
| 265 | + cmd = re.sub('(%)?%i','%s' % location, func) | |
| 266 | + # add PYTHONPATH at the beginning, | |
| 267 | + cmd = "%s 2> /dev/null" % cmd | |
| 268 | + for each in runcommand(cmd): | |
| 269 | + req.write("%s\n"%each) | |
| 270 | + | |
| 271 | +# play ogg foo | |
| 272 | +def play_ogg(req): | |
| 273 | + req.content_type = "application/ogg" | |
| 274 | + func = "oggenc -o - %%i" | |
| 275 | + # build location (strip the func_path, add DATADIR) | |
| 276 | + location = re.sub('^/play_ogg/','%s/'%DATADIR,req.path_info) | |
| 277 | + location = re.sub('.ogg$','',location) | |
| 278 | + if not os.path.isfile(location): | |
| 279 | + from mod_python import apache | |
| 280 | + raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND | |
| 281 | + # replace location in func | |
| 282 | + cmd = re.sub('(%)?%i','%s' % location, func) | |
| 283 | + # add PYTHONPATH at the beginning, | |
| 284 | + cmd = "%s 2> /dev/null" % cmd | |
| 285 | + for each in runcommand(cmd): | |
| 286 | + req.write("%s\n"%each) | |
| @@ -0,0 +1,17 @@ | ||
| 1 | +# vim:set syntax=python: | |
| 2 | + | |
| 3 | +pyaubio = ctx.new_task_gen(name = 'python-aubio', | |
| 4 | + features = 'c cshlib pyext', | |
| 5 | + source = '../../swig/aubio.i', | |
| 6 | + add_objects = 'sndfileio', | |
| 7 | + target = '_aubiowrapper', | |
| 8 | + use = ['aubio'], | |
| 9 | + uselib = ['SNDFILE'], | |
| 10 | + swig_flags = '-python -Wall', | |
| 11 | + includes = '. ../../src ../../examples') | |
| 12 | +pyaubio.install_path = '${PYTHONDIR}/${PACKAGE}' | |
| 13 | + | |
| 14 | +# install python files | |
| 15 | +ctx.install_files('${PYTHONDIR}/${PACKAGE}/', ctx.path.ant_glob('**/*.py')) | |
| 16 | +# install swig generated python file | |
| 17 | +ctx.install_files('${PYTHONDIR}/${PACKAGE}/', '../../swig/aubiowrapper.py') | |