source: python/aubio/tasks.py @ 677b267

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

start using results structure, move onset specific out of node
start using results structure, move onset specific out of node

  • Property mode set to 100644
File size: 18.4 KB
RevLine 
[5e491b3b]1from aubioclass import * 
[0029638]2from bench.node import bench
[5e491b3b]3
[7473074]4def get_onset_mode(nvalue):
[5e491b3b]5        """ utility function to convert a string to aubio_onsetdetection_type """
[7473074]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
[0029638]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
[7473074]42def check_onset_mode(option, opt, value, parser):
43        """ wrapper function to convert a list of modes to
44                aubio_onsetdetection_type """
[5e491b3b]45        nvalues = parser.rargs[0].split(',')
46        val =  []
47        for nvalue in nvalues:
[7473074]48                val.append(get_onset_mode(nvalue))
[5e491b3b]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:
[0029638]56                val.append(get_pitch_mode(nvalue))
[5e491b3b]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
[d9101a5]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
[5e491b3b]196
[0029638]197
[c32976a5]198class taskparams(object):
[0029638]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
[7c9ad74]204                self.storefunc = False
[0029638]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
[7c9ad74]211                self.onsetmode = 'dual'
212                self.pitchmode = 'yin'
[0029638]213                self.omode = aubio_pitchm_freq
214
215class task(taskparams):
[7c9ad74]216        """ default template class to apply tasks on a stream """
[0029638]217        def __init__(self,input,output=None,params=None):
[7c9ad74]218                """ open the input file and initialize default argument
219                parameters should be set *before* calling this method.
220                """
[d9101a5]221                import time
222                self.tic = time.time()
[0029638]223                if params == None: self.params = taskparams()
224                else: self.params = params
[7c9ad74]225                self.frameread = 0
226                self.readsize  = self.params.hopsize
[0029638]227                self.input     = input
228                self.filei     = sndfile(self.input)
229                self.srate     = self.filei.samplerate()
230                self.channels  = self.filei.channels()
[7c9ad74]231                self.step      = float(self.srate)/float(self.params.hopsize)
232                self.myvec     = fvec(self.params.hopsize,self.channels)
[0029638]233                self.output    = output
[d9101a5]234
[7c9ad74]235        def __call__(self):
236                self.readsize = self.filei.read(self.params.hopsize,self.myvec)
237                self.frameread += 1
238               
[0029638]239        def compute_all(self):
240                """ Compute data """
241                mylist    = []
242                while(self.readsize==self.params.hopsize):
[7c9ad74]243                        tmp = self()
244                        if tmp: mylist.append(tmp)
[0029638]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
[d9101a5]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
[7c9ad74]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
[0029638]278class taskpitch(task):
279        def __init__(self,input,params=None):
280                task.__init__(self,input,params=params)
[7c9ad74]281                self.pitchdet  = pitchdetection(mode=get_pitch_mode(self.params.pitchmode),
[0029638]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)
[7c9ad74]290                task.__call__(self)
291                freq = self.pitchdet(self.myvec)
[0029638]292                if (aubio_silence_detection(self.myvec(),self.params.silence)!=1):
293                        return freq
294                else: 
295                        return -1.
296
297        def gettruth(self):
[7c9ad74]298                """ big hack to extract midi note from /path/to/file.<midinote>.wav """
[c32976a5]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
[0029638]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
[7c9ad74]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))
[0029638]323                avgdist = self.truth - avg
324                meddist = self.truth - med
325                return avgdist, meddist
326
[d9101a5]327        def plot(self,pitch,outplot=None):
[0029638]328                from aubio.gnuplot import plot_pitch
329                plot_pitch(self.input, 
330                        pitch, 
[d9101a5]331                        samplerate=float(self.srate), 
[0029638]332                        hopsize=self.params.hopsize, 
[d9101a5]333                        outplot=outplot)
[0029638]334
335
[7c9ad74]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:
[c32976a5]354                        self.ovalist   = [0., 0., 0., 0., 0.]
[7c9ad74]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:
[c32976a5]364                        if val > 0: self.ovalist.append(val)
365                        else: self.ovalist.append(0)
366                        self.ovalist.pop(0)
[7c9ad74]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
[c32976a5]380
[4045ba4]381        def eval(self,inputdata,ftru,mode='roc',vmode=''):
[7c9ad74]382                from txtfile import read_datafile
[4045ba4]383                from onsetcompare import onset_roc, onset_diffs, onset_rocloc
[c32976a5]384                ltru = read_datafile(ftru,depth=0)
[4045ba4]385                lres = []
386                for i in range(len(inputdata)): lres.append(inputdata[i][0]*self.params.step)
[7c9ad74]387                if vmode=='verbose':
[4045ba4]388                        print "Running with mode %s" % self.params.onsetmode, 
[7c9ad74]389                        print " and threshold %f" % self.params.threshold, 
[4045ba4]390                        print " on file", self.input
[7c9ad74]391                #print ltru; print lres
[4045ba4]392                if mode == 'local':
[7c9ad74]393                        l = onset_diffs(ltru,lres,self.params.tol)
394                        mean = 0
395                        for i in l: mean += i
[4045ba4]396                        if len(l): mean = "%.3f" % (mean/len(l))
397                        else: mean = "?0"
398                        return l, mean
399                elif mode == 'roc':
[7c9ad74]400                        self.orig, self.missed, self.merged, \
401                                self.expc, self.bad, self.doubled = \
402                                onset_roc(ltru,lres,self.params.tol)
[4045ba4]403                elif mode == 'rocloc':
[dbc0351]404                        self.v = {}
405                        self.v['orig'], self.v['missed'], self.v['Tm'], \
406                                self.v['expc'], self.v['bad'], self.v['Td'], \
407                                self.v['l'], self.v['labs'] = \
[4045ba4]408                                onset_rocloc(ltru,lres,self.params.tol)
[7c9ad74]409
410        def plot(self,onsets,ofunc):
411                import Gnuplot, Gnuplot.funcutils
412                import aubio.txtfile
413                import os.path
414                import numarray
415                from aubio.onsetcompare import onset_roc
416
417                self.lenofunc = len(ofunc) 
418                self.maxofunc = max(max(ofunc), self.maxofunc)
419                # onset detection function
420                downtime = numarray.arange(len(ofunc))/self.step
421                self.d.append(Gnuplot.Data(downtime,ofunc,with='lines'))
422
423                # detected onsets
424                x1 = numarray.array(onsets)/self.step
425                y1 = self.maxofunc*numarray.ones(len(onsets))
426                self.d.append(Gnuplot.Data(x1,y1,with='impulses'))
427                self.d2.append(Gnuplot.Data(x1,-y1,with='impulses'))
428
429                # check if datafile exists truth
430                datafile = self.input.replace('.wav','.txt')
431                if datafile == self.input: datafile = ""
432                if not os.path.isfile(datafile):
433                        self.title = "truth file not found"
434                        t = Gnuplot.Data(0,0,with='impulses') 
435                else:
436                        t_onsets = aubio.txtfile.read_datafile(datafile)
437                        y2 = self.maxofunc*numarray.ones(len(t_onsets))
438                        x2 = numarray.array(t_onsets).resize(len(t_onsets))
439                        self.d2.append(Gnuplot.Data(x2,y2,with='impulses'))
440                       
441                        tol = 0.050 
[0029638]442
[7c9ad74]443                        orig, missed, merged, expc, bad, doubled = \
444                                onset_roc(x2,x1,tol)
445                        self.title = "GD %2.3f%% FP %2.3f%%" % \
446                                ((100*float(orig-missed-merged)/(orig)),
447                                 (100*float(bad+doubled)/(orig)))
448
449
450        def plotplot(self,outplot=None):
451                from aubio.gnuplot import gnuplot_init, audio_to_array, make_audio_plot
452                import re
453                # audio data
454                time,data = audio_to_array(self.input)
455                self.d2.append(make_audio_plot(time,data))
456                # prepare the plot
457                g = gnuplot_init(outplot)
458
459                g('set title \'%s %s\'' % (re.sub('.*/','',self.input),self.title))
460
461                g('set multiplot')
462
463                # hack to align left axis
464                g('set lmargin 15')
465
466                # plot waveform and onsets
467                g('set size 1,0.3')
468                g('set origin 0,0.7')
469                g('set xrange [0:%f]' % max(time)) 
470                g('set yrange [-1:1]') 
471                g.ylabel('amplitude')
472                g.plot(*self.d2)
473               
474                g('unset title')
475
476                # plot onset detection function
477                g('set size 1,0.7')
478                g('set origin 0,0')
479                g('set xrange [0:%f]' % (self.lenofunc/self.step))
480                g('set yrange [0:%f]' % (self.maxofunc*1.01))
481                g.xlabel('time')
482                g.ylabel('onset detection value')
483                g.plot(*self.d)
484
485                g('unset multiplot')
486
487class taskcut(task):
488        def __init__(self,input,slicetimes,params=None,output=None):
489                """ open the input file and initialize arguments
490                parameters should be set *before* calling this method.
491                """
492                task.__init__(self,input,output=None,params=params)
493                self.newname   = "%s%s%09.5f%s%s" % (self.input.split(".")[0].split("/")[-1],".",
494                                        self.frameread/self.step,".",self.input.split(".")[-1])
495                self.fileo       = sndfile(self.newname,model=self.filei)
496                self.myvec       = fvec(self.params.hopsize,self.channels)
497                self.mycopy     = fvec(self.params.hopsize,self.channels)
498                self.slicetimes = slicetimes
499
500        def __call__(self):
501                task.__call__(self)
502                # write to current file
503                if len(self.slicetimes) and self.frameread >= self.slicetimes[0]:
504                        self.slicetimes.pop(0)
505                        # write up to 1st zero crossing
506                        zerocross = 0
507                        while ( abs( self.myvec.get(zerocross,0) ) > self.params.zerothres ):
508                                zerocross += 1
509                        writesize = self.fileo.write(zerocross,self.myvec)
510                        fromcross = 0
511                        while (zerocross < self.readsize):
512                                for i in range(self.channels):
513                                        self.mycopy.set(self.myvec.get(zerocross,i),fromcross,i)
514                                        fromcross += 1
515                                        zerocross += 1
516                        del self.fileo
517                        self.fileo = sndfile("%s%s%09.5f%s%s" % 
518                                (self.input.split(".")[0].split("/")[-1],".",
519                                self.frameread/self.step,".",self.input.split(".")[-1]),model=self.filei)
520                        writesize = self.fileo.write(fromcross,self.mycopy)
521                else:
522                        writesize = self.fileo.write(self.readsize,self.myvec)
[c32976a5]523
524class taskbeat(taskonset):
525        def __init__(self,input,params=None,output=None):
526                """ open the input file and initialize arguments
527                parameters should be set *before* calling this method.
528                """
529                taskonset.__init__(self,input,output=None,params=params)
530                self.btwinlen  = 512**2/self.params.hopsize
531                self.btstep    = self.btwinlen/4
532                self.btoutput  = fvec(self.btstep,self.channels)
533                self.dfframe   = fvec(self.btwinlen,self.channels)
534                self.bt        = beattracking(self.btwinlen,self.channels)
535                self.pos2      = 0
536
537        def __call__(self):
538                taskonset.__call__(self)
539                # write to current file
540                if self.pos2 == self.btstep - 1 : 
541                        self.bt.do(self.dfframe,self.btoutput)
542                        for i in range (self.btwinlen - self.btstep):
543                                self.dfframe.set(self.dfframe.get(i+self.btstep,0),i,0) 
544                        for i in range(self.btwinlen - self.btstep, self.btwinlen): 
545                                self.dfframe.set(0,i,0)
546                        self.pos2 = -1;
547                self.pos2 += 1
548                val = self.opick.pp.getval()
549                self.dfframe.set(val,self.btwinlen - self.btstep + self.pos2,0)
550                i=0
551                for i in range(1,int( self.btoutput.get(0,0) ) ):
552                        if self.pos2 == self.btoutput.get(i,0) and \
553                                aubio_silence_detection(self.myvec(),
554                                        self.params.silence)!=1: 
555                                return self.frameread, 0 
556       
557        def eval(self,results):
558                pass
Note: See TracBrowser for help on using the repository browser.