source: python/aubio/tasks.py @ 4045ba4

feature/autosinkfeature/cnnfeature/cnn_orgfeature/constantqfeature/crepefeature/crepe_orgfeature/pitchshiftfeature/pydocstringsfeature/timestretchfix/ffmpeg5pitchshiftsamplertimestretchyinfft+
Last change on this file since 4045ba4 was 4045ba4, checked in by Paul Brossier <piem@altern.org>, 19 years ago

remove gettruth from onset, add rocloc evaluation mode
remove gettruth from onset, add rocloc evaluation mode

  • Property mode set to 100644
File size: 18.4 KB
Line 
1from aubioclass import * 
2from bench.node import bench
3
4def get_onset_mode(nvalue):
5        """ utility function to convert a string to aubio_onsetdetection_type """
6        if   nvalue == 'complexdomain' or nvalue == 'complex' :
7                 return aubio_onset_complex
8        elif nvalue == 'hfc'           :
9                 return aubio_onset_hfc
10        elif nvalue == 'phase'         :
11                 return aubio_onset_phase
12        elif nvalue == 'specdiff'      :
13                 return aubio_onset_specdiff
14        elif nvalue == 'energy'        :
15                 return aubio_onset_energy
16        elif nvalue == 'kl'            :
17                 return aubio_onset_kl
18        elif nvalue == 'mkl'           :
19                 return aubio_onset_mkl
20        elif nvalue == 'dual'          :
21                 return 'dual'
22        else:
23                 import sys
24                 print "unknown onset detection function selected"
25                 sys.exit(1)
26
27def get_pitch_mode(nvalue):
28        """ utility function to convert a string to aubio_pitchdetection_type """
29        if   nvalue == 'mcomb'  :
30                 return aubio_pitch_mcomb
31        elif nvalue == 'yin'    :
32                 return aubio_pitch_yin
33        elif nvalue == 'fcomb'  :
34                 return aubio_pitch_fcomb
35        elif nvalue == 'schmitt':
36                 return aubio_pitch_schmitt
37        else:
38                 import sys
39                 print "error: unknown pitch detection function selected"
40                 sys.exit(1)
41
42def check_onset_mode(option, opt, value, parser):
43        """ wrapper function to convert a list of modes to
44                aubio_onsetdetection_type """
45        nvalues = parser.rargs[0].split(',')
46        val =  []
47        for nvalue in nvalues:
48                val.append(get_onset_mode(nvalue))
49                setattr(parser.values, option.dest, val)
50
51def check_pitch_mode(option, opt, value, parser):
52        """ utility function to convert a string to aubio_pitchdetection_type"""
53        nvalues = parser.rargs[0].split(',')
54        val = []
55        for nvalue in nvalues:
56                val.append(get_pitch_mode(nvalue))
57                setattr(parser.values, option.dest, val)
58
59def check_pitchm_mode(option, opt, value, parser):
60        """ utility function to convert a string to aubio_pitchdetection_mode """
61        nvalue = parser.rargs[0]
62        if   nvalue == 'freq'  :
63                 setattr(parser.values, option.dest, aubio_pitchm_freq)
64        elif nvalue == 'midi'  :
65                 setattr(parser.values, option.dest, aubio_pitchm_midi)
66        elif nvalue == 'cent'  :
67                 setattr(parser.values, option.dest, aubio_pitchm_cent)
68        elif nvalue == 'bin'   :
69                 setattr(parser.values, option.dest, aubio_pitchm_bin)
70        else:
71                 import sys
72                 print "error: unknown pitch detection output selected"
73                 sys.exit(1)
74
75
76#def getonsets(filein,threshold=0.2,silence=-70.,bufsize=1024,hopsize=512,
77#                mode='dual',localmin=False,storefunc=False,derivate=False):
78#        frameread = 0
79#        filei     = sndfile(filein)
80#        channels  = filei.channels()
81#        myvec     = fvec(hopsize,channels)
82#        readsize  = filei.read(hopsize,myvec)
83#        opick     = onsetpick(bufsize,hopsize,channels,myvec,threshold,
84#                         mode=mode,derivate=derivate)
85#        mylist    = list()
86#        if localmin:
87#                ovalist   = [0., 0., 0., 0., 0.]
88#        ofunclist = []
89#        while(readsize):
90#                readsize = filei.read(hopsize,myvec)
91#                isonset,val = opick.do(myvec)
92#                if (aubio_silence_detection(myvec(),silence)):
93#                        isonset=0
94#                if localmin:
95#                        if val > 0: ovalist.append(val)
96#                        else: ovalist.append(0)
97#                        ovalist.pop(0)
98#                if storefunc:
99#                        ofunclist.append(val)
100#                if (isonset == 1):
101#                        if localmin:
102#                                i=len(ovalist)-1
103#                                # find local minima before peak
104#                                while ovalist[i-1] < ovalist[i] and i > 0:
105#                                        i -= 1
106#                                now = (frameread+1-i)
107#                        else:
108#                                now = frameread
109#                        if now > 0 :
110#                                mylist.append(now)
111#                        else:
112#                                now = 0
113#                                mylist.append(now)
114#                frameread += 1
115#        return mylist, ofunclist
116#
117#def cutfile(filein,slicetimes,zerothres=0.008,bufsize=1024,hopsize=512):
118#    frameread = 0
119#    readsize  = hopsize
120#    filei     = sndfile(filein)
121#    framestep = hopsize/(filei.samplerate()+0.)
122#    channels  = filei.channels()
123#    newname   = "%s%s%09.5f%s%s" % (filein.split(".")[0].split("/")[-1],".",
124#                frameread*framestep,".",filein.split(".")[-1])
125#    fileo     = sndfile(newname,model=filei)
126#    myvec     = fvec(hopsize,channels)
127#    mycopy    = fvec(hopsize,channels)
128#    while(readsize==hopsize):
129#        readsize = filei.read(hopsize,myvec)
130#        # write to current file
131#        if len(slicetimes) and frameread >= slicetimes[0]:
132#            slicetimes.pop(0)
133#            # write up to 1st zero crossing
134#            zerocross = 0
135#            while ( abs( myvec.get(zerocross,0) ) > zerothres ):
136#                zerocross += 1
137#            writesize = fileo.write(zerocross,myvec)
138#            fromcross = 0
139#            while (zerocross < readsize):
140#                for i in range(channels):
141#                    mycopy.set(myvec.get(zerocross,i),fromcross,i)
142#                    fromcross += 1
143#                    zerocross += 1
144#            del fileo
145#            fileo = sndfile("%s%s%09.5f%s%s" %
146#                (filein.split(".")[0].split("/")[-1],".",
147#                frameread*framestep,".",filein.split(".")[-1]),model=filei)
148#            writesize = fileo.write(fromcross,mycopy)
149#        else:
150#            writesize = fileo.write(readsize,myvec)
151#        frameread += 1
152#    del fileo
153#
154#
155#def getsilences(filein,hopsize=512,silence=-70):
156#    frameread = 0
157#    filei     = sndfile(filein)
158#    srate     = filei.samplerate()
159#    channels  = filei.channels()
160#    myvec     = fvec(hopsize,channels)
161#    readsize  = filei.read(hopsize,myvec)
162#    mylist    = []
163#    wassilence = 0
164#    while(readsize==hopsize):
165#        readsize = filei.read(hopsize,myvec)
166#        if (aubio_silence_detection(myvec(),silence)==1):
167#            if wassilence == 0:
168#                mylist.append(frameread)
169#                wassilence == 1
170#        else: wassilence = 0
171#        frameread += 1
172#    return mylist
173#
174#
175#def getpitch(filein,mode=aubio_pitch_mcomb,bufsize=1024,hopsize=512,omode=aubio_pitchm_freq,
176#        samplerate=44100.,silence=-70):
177#    frameread = 0
178#    filei     = sndfile(filein)
179#    srate     = filei.samplerate()
180#    channels  = filei.channels()
181#    myvec     = fvec(hopsize,channels)
182#    readsize  = filei.read(hopsize,myvec)
183#    pitchdet  = pitchdetection(mode=mode,bufsize=bufsize,hopsize=hopsize,
184#                         channels=channels,samplerate=srate,omode=omode)
185#    mylist    = []
186#    while(readsize==hopsize):
187#        readsize = filei.read(hopsize,myvec)
188#        freq = pitchdet(myvec)
189#        #print "%.3f     %.2f" % (now,freq)
190#        if (aubio_silence_detection(myvec(),silence)!=1):
191#                mylist.append(freq)
192#        else:
193#                mylist.append(-1.)
194#        frameread += 1
195#    return mylist
196
197
198class taskparams(object):
199        """ default parameters for task classes """
200        def __init__(self,input=None,output=None):
201                self.silence = -70
202                self.derivate = False
203                self.localmin = False
204                self.storefunc = False
205                self.bufsize = 512
206                self.hopsize = 256
207                self.samplerate = 44100
208                self.tol = 0.05
209                self.step = float(self.hopsize)/float(self.samplerate)
210                self.threshold = 0.1
211                self.onsetmode = 'dual'
212                self.pitchmode = 'yin'
213                self.omode = aubio_pitchm_freq
214
215class task(taskparams):
216        """ default template class to apply tasks on a stream """
217        def __init__(self,input,output=None,params=None):
218                """ open the input file and initialize default argument
219                parameters should be set *before* calling this method.
220                """
221                import time
222                self.tic = time.time()
223                if params == None: self.params = taskparams()
224                else: self.params = params
225                self.frameread = 0
226                self.readsize  = self.params.hopsize
227                self.input     = input
228                self.filei     = sndfile(self.input)
229                self.srate     = self.filei.samplerate()
230                self.channels  = self.filei.channels()
231                self.step      = float(self.srate)/float(self.params.hopsize)
232                self.myvec     = fvec(self.params.hopsize,self.channels)
233                self.output    = output
234
235        def __call__(self):
236                self.readsize = self.filei.read(self.params.hopsize,self.myvec)
237                self.frameread += 1
238               
239        def compute_all(self):
240                """ Compute data """
241                mylist    = []
242                while(self.readsize==self.params.hopsize):
243                        tmp = self()
244                        if tmp: mylist.append(tmp)
245                return mylist
246
247        def eval(self,results):
248                """ Eval data """
249                pass
250
251        def plot(self):
252                """ Plot data """
253                pass
254
255        def time(self):
256                import time
257                print "CPU time is now %f seconds," % time.clock(),
258                print "task execution took %f seconds" % (time.time() - self.tic)
259
260class tasksilence(task):
261        wassilence = 1
262        issilence  = 1
263        def __call__(self):
264                task.__call__(self)
265                if (aubio_silence_detection(self.myvec(),self.params.silence)==1):
266                        if self.wassilence == 1: self.issilence = 1
267                        else: self.issilence = 2
268                        self.wassilence = 1
269                else: 
270                        if self.wassilence <= 0: self.issilence = 0
271                        else: self.issilence = -1 
272                        self.wassilence = 0
273                if self.issilence == -1:
274                        return -1, self.frameread
275                elif self.issilence == 2:
276                        return 2, self.frameread
277
278class taskpitch(task):
279        def __init__(self,input,params=None):
280                task.__init__(self,input,params=params)
281                self.pitchdet  = pitchdetection(mode=get_pitch_mode(self.params.pitchmode),
282                        bufsize=self.params.bufsize,
283                        hopsize=self.params.hopsize,
284                        channels=self.channels,
285                        samplerate=self.srate,
286                        omode=self.params.omode)
287
288        def __call__(self):
289                #print "%.3f     %.2f" % (now,freq)
290                task.__call__(self)
291                freq = self.pitchdet(self.myvec)
292                if (aubio_silence_detection(self.myvec(),self.params.silence)!=1):
293                        return freq
294                else: 
295                        return -1.
296
297        def gettruth(self):
298                """ big hack to extract midi note from /path/to/file.<midinote>.wav """
299                floatpit = self.input.split('.')[-2]
300                try:
301                        return float(floatpit)
302                except ValueError:
303                        print "ERR: no truth file found"
304                        return 0
305
306        def eval(self,results):
307                from median import short_find
308                self.truth = self.gettruth()
309                num = 0
310                sum = 0
311                res = []
312                for i in results:
313                        if i == -1: pass
314                        else: 
315                                res.append(i)
316                                sum += i
317                                num += 1
318                if num == 0: 
319                        avg = 0; med = 0
320                else:
321                        avg = aubio_freqtomidi(sum / float(num))
322                        med = aubio_freqtomidi(short_find(res,len(res)/2))
323                avgdist = self.truth - avg
324                meddist = self.truth - med
325                return avgdist, meddist
326
327        def plot(self,pitch,outplot=None):
328                from aubio.gnuplot import plot_pitch
329                plot_pitch(self.input, 
330                        pitch, 
331                        samplerate=float(self.srate), 
332                        hopsize=self.params.hopsize, 
333                        outplot=outplot)
334
335
336class taskonset(task):
337        def __init__(self,input,output=None,params=None):
338                """ open the input file and initialize arguments
339                parameters should be set *before* calling this method.
340                """
341                task.__init__(self,input,params=params)
342                self.opick = onsetpick(self.params.bufsize,
343                        self.params.hopsize,
344                        self.channels,
345                        self.myvec,
346                        self.params.threshold,
347                        mode=get_onset_mode(self.params.onsetmode),
348                        derivate=self.params.derivate)
349                self.olist = [] 
350                self.ofunc = []
351                self.d,self.d2 = [],[]
352                self.maxofunc = 0
353                if self.params.localmin:
354                        self.ovalist   = [0., 0., 0., 0., 0.]
355
356        def __call__(self):
357                task.__call__(self)
358                isonset,val = self.opick.do(self.myvec)
359                if (aubio_silence_detection(self.myvec(),self.params.silence)):
360                        isonset=0
361                if self.params.storefunc:
362                        self.ofunc.append(val)
363                if self.params.localmin:
364                        if val > 0: self.ovalist.append(val)
365                        else: self.ovalist.append(0)
366                        self.ovalist.pop(0)
367                if (isonset == 1):
368                        if self.params.localmin:
369                                i=len(self.ovalist)-1
370                                # find local minima before peak
371                                while self.ovalist[i-1] < self.ovalist[i] and i > 0:
372                                        i -= 1
373                                now = (self.frameread+1-i)
374                        else:
375                                now = self.frameread
376                        if now < 0 :
377                                now = 0
378                        return now, val
379
380
381        def eval(self,inputdata,ftru,mode='roc',vmode=''):
382                from txtfile import read_datafile
383                from onsetcompare import onset_roc, onset_diffs, onset_rocloc
384                ltru = read_datafile(ftru,depth=0)
385                lres = []
386                for i in range(len(inputdata)): lres.append(inputdata[i][0]*self.params.step)
387                if vmode=='verbose':
388                        print "Running with mode %s" % self.params.onsetmode, 
389                        print " and threshold %f" % self.params.threshold, 
390                        print " on file", self.input
391                #print ltru; print lres
392                if mode == 'local':
393                        l = onset_diffs(ltru,lres,self.params.tol)
394                        mean = 0
395                        for i in l: mean += i
396                        if len(l): mean = "%.3f" % (mean/len(l))
397                        else: mean = "?0"
398                        return l, mean
399                elif mode == 'roc':
400                        self.orig, self.missed, self.merged, \
401                                self.expc, self.bad, self.doubled = \
402                                onset_roc(ltru,lres,self.params.tol)
403                elif mode == 'rocloc':
404                        self.orig, self.missed, self.merged, \
405                                self.expc, self.bad, self.doubled, \
406                                self.l, self.mean = \
407                                onset_rocloc(ltru,lres,self.params.tol)
408
409        def plot(self,onsets,ofunc):
410                import Gnuplot, Gnuplot.funcutils
411                import aubio.txtfile
412                import os.path
413                import numarray
414                from aubio.onsetcompare import onset_roc
415
416                self.lenofunc = len(ofunc) 
417                self.maxofunc = max(max(ofunc), self.maxofunc)
418                # onset detection function
419                downtime = numarray.arange(len(ofunc))/self.step
420                self.d.append(Gnuplot.Data(downtime,ofunc,with='lines'))
421
422                # detected onsets
423                x1 = numarray.array(onsets)/self.step
424                y1 = self.maxofunc*numarray.ones(len(onsets))
425                self.d.append(Gnuplot.Data(x1,y1,with='impulses'))
426                self.d2.append(Gnuplot.Data(x1,-y1,with='impulses'))
427
428                # check if datafile exists truth
429                datafile = self.input.replace('.wav','.txt')
430                if datafile == self.input: datafile = ""
431                if not os.path.isfile(datafile):
432                        self.title = "truth file not found"
433                        t = Gnuplot.Data(0,0,with='impulses') 
434                else:
435                        t_onsets = aubio.txtfile.read_datafile(datafile)
436                        y2 = self.maxofunc*numarray.ones(len(t_onsets))
437                        x2 = numarray.array(t_onsets).resize(len(t_onsets))
438                        self.d2.append(Gnuplot.Data(x2,y2,with='impulses'))
439                       
440                        tol = 0.050 
441
442                        orig, missed, merged, expc, bad, doubled = \
443                                onset_roc(x2,x1,tol)
444                        self.title = "GD %2.3f%% FP %2.3f%%" % \
445                                ((100*float(orig-missed-merged)/(orig)),
446                                 (100*float(bad+doubled)/(orig)))
447
448
449        def plotplot(self,outplot=None):
450                from aubio.gnuplot import gnuplot_init, audio_to_array, make_audio_plot
451                import re
452                # audio data
453                time,data = audio_to_array(self.input)
454                self.d2.append(make_audio_plot(time,data))
455                # prepare the plot
456                g = gnuplot_init(outplot)
457
458                g('set title \'%s %s\'' % (re.sub('.*/','',self.input),self.title))
459
460                g('set multiplot')
461
462                # hack to align left axis
463                g('set lmargin 15')
464
465                # plot waveform and onsets
466                g('set size 1,0.3')
467                g('set origin 0,0.7')
468                g('set xrange [0:%f]' % max(time)) 
469                g('set yrange [-1:1]') 
470                g.ylabel('amplitude')
471                g.plot(*self.d2)
472               
473                g('unset title')
474
475                # plot onset detection function
476                g('set size 1,0.7')
477                g('set origin 0,0')
478                g('set xrange [0:%f]' % (self.lenofunc/self.step))
479                g('set yrange [0:%f]' % (self.maxofunc*1.01))
480                g.xlabel('time')
481                g.ylabel('onset detection value')
482                g.plot(*self.d)
483
484                g('unset multiplot')
485
486class taskcut(task):
487        def __init__(self,input,slicetimes,params=None,output=None):
488                """ open the input file and initialize arguments
489                parameters should be set *before* calling this method.
490                """
491                task.__init__(self,input,output=None,params=params)
492                self.newname   = "%s%s%09.5f%s%s" % (self.input.split(".")[0].split("/")[-1],".",
493                                        self.frameread/self.step,".",self.input.split(".")[-1])
494                self.fileo       = sndfile(self.newname,model=self.filei)
495                self.myvec       = fvec(self.params.hopsize,self.channels)
496                self.mycopy     = fvec(self.params.hopsize,self.channels)
497                self.slicetimes = slicetimes
498
499        def __call__(self):
500                task.__call__(self)
501                # write to current file
502                if len(self.slicetimes) and self.frameread >= self.slicetimes[0]:
503                        self.slicetimes.pop(0)
504                        # write up to 1st zero crossing
505                        zerocross = 0
506                        while ( abs( self.myvec.get(zerocross,0) ) > self.params.zerothres ):
507                                zerocross += 1
508                        writesize = self.fileo.write(zerocross,self.myvec)
509                        fromcross = 0
510                        while (zerocross < self.readsize):
511                                for i in range(self.channels):
512                                        self.mycopy.set(self.myvec.get(zerocross,i),fromcross,i)
513                                        fromcross += 1
514                                        zerocross += 1
515                        del self.fileo
516                        self.fileo = sndfile("%s%s%09.5f%s%s" % 
517                                (self.input.split(".")[0].split("/")[-1],".",
518                                self.frameread/self.step,".",self.input.split(".")[-1]),model=self.filei)
519                        writesize = self.fileo.write(fromcross,self.mycopy)
520                else:
521                        writesize = self.fileo.write(self.readsize,self.myvec)
522
523class taskbeat(taskonset):
524        def __init__(self,input,params=None,output=None):
525                """ open the input file and initialize arguments
526                parameters should be set *before* calling this method.
527                """
528                taskonset.__init__(self,input,output=None,params=params)
529                self.btwinlen  = 512**2/self.params.hopsize
530                self.btstep    = self.btwinlen/4
531                self.btoutput  = fvec(self.btstep,self.channels)
532                self.dfframe   = fvec(self.btwinlen,self.channels)
533                self.bt        = beattracking(self.btwinlen,self.channels)
534                self.pos2      = 0
535
536        def __call__(self):
537                taskonset.__call__(self)
538                # write to current file
539                if self.pos2 == self.btstep - 1 : 
540                        self.bt.do(self.dfframe,self.btoutput)
541                        for i in range (self.btwinlen - self.btstep):
542                                self.dfframe.set(self.dfframe.get(i+self.btstep,0),i,0) 
543                        for i in range(self.btwinlen - self.btstep, self.btwinlen): 
544                                self.dfframe.set(0,i,0)
545                        self.pos2 = -1;
546                self.pos2 += 1
547                val = self.opick.pp.getval()
548                self.dfframe.set(val,self.btwinlen - self.btstep + self.pos2,0)
549                i=0
550                for i in range(1,int( self.btoutput.get(0,0) ) ):
551                        if self.pos2 == self.btoutput.get(i,0) and \
552                                aubio_silence_detection(self.myvec(),
553                                        self.params.silence)!=1: 
554                                return self.frameread, 0 
555       
556        def eval(self,results):
557                pass
Note: See TracBrowser for help on using the repository browser.