source: python/aubio/tasks.py @ 0484dc1

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

added support for dcthres and verbose, moved task.step to tasks.params.step, updated plot functions
added support for dcthres and verbose, moved task.step to tasks.params.step, updated plot functions

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