source: python/aubio/tasks.py @ e8d0c06

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

add taskbeat, make taskparams an object subclass, fix bug on localmin
add taskbeat, make taskparams an object subclass, fix bug on localmin

  • Property mode set to 100644
File size: 18.1 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
76def 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
117def 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
155def 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
175def 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                if params == None: self.params = taskparams()
222                else: self.params = params
223                self.frameread = 0
224                self.readsize  = self.params.hopsize
225                self.input     = input
226                self.filei     = sndfile(self.input)
227                self.srate     = self.filei.samplerate()
228                self.channels  = self.filei.channels()
229                self.step      = float(self.srate)/float(self.params.hopsize)
230                self.myvec     = fvec(self.params.hopsize,self.channels)
231                self.output    = output
232        def __call__(self):
233                self.readsize = self.filei.read(self.params.hopsize,self.myvec)
234                self.frameread += 1
235               
236        def compute_all(self):
237                """ Compute data """
238                mylist    = []
239                while(self.readsize==self.params.hopsize):
240                        tmp = self()
241                        if tmp: mylist.append(tmp)
242                return mylist
243
244        def eval(self,results):
245                """ Eval data """
246                pass
247
248        def plot(self):
249                """ Plot data """
250                pass
251
252class tasksilence(task):
253        wassilence = 1
254        issilence  = 1
255        def __call__(self):
256                task.__call__(self)
257                if (aubio_silence_detection(self.myvec(),self.params.silence)==1):
258                        if self.wassilence == 1: self.issilence = 1
259                        else: self.issilence = 2
260                        self.wassilence = 1
261                else: 
262                        if self.wassilence <= 0: self.issilence = 0
263                        else: self.issilence = -1 
264                        self.wassilence = 0
265                if self.issilence == -1:
266                        return -1, self.frameread
267                elif self.issilence == 2:
268                        return 2, self.frameread
269
270class taskpitch(task):
271        def __init__(self,input,params=None):
272                task.__init__(self,input,params=params)
273                self.pitchdet  = pitchdetection(mode=get_pitch_mode(self.params.pitchmode),
274                        bufsize=self.params.bufsize,
275                        hopsize=self.params.hopsize,
276                        channels=self.channels,
277                        samplerate=self.srate,
278                        omode=self.params.omode)
279
280        def __call__(self):
281                #print "%.3f     %.2f" % (now,freq)
282                task.__call__(self)
283                freq = self.pitchdet(self.myvec)
284                if (aubio_silence_detection(self.myvec(),self.params.silence)!=1):
285                        return freq
286                else: 
287                        return -1.
288
289        def gettruth(self):
290                """ big hack to extract midi note from /path/to/file.<midinote>.wav """
291                floatpit = self.input.split('.')[-2]
292                try:
293                        return float(floatpit)
294                except ValueError:
295                        print "ERR: no truth file found"
296                        return 0
297
298        def eval(self,results):
299                from median import short_find
300                self.truth = self.gettruth()
301                num = 0
302                sum = 0
303                res = []
304                for i in results:
305                        if i == -1: pass
306                        else: 
307                                res.append(i)
308                                sum += i
309                                num += 1
310                if num == 0: 
311                        avg = 0; med = 0
312                else:
313                        avg = aubio_freqtomidi(sum / float(num))
314                        med = aubio_freqtomidi(short_find(res,len(res)/2))
315                avgdist = self.truth - avg
316                meddist = self.truth - med
317                return avgdist, meddist
318
319        def plot(self):
320                from aubio.gnuplot import plot_pitch
321                plot_pitch(self.input, 
322                        pitch, 
323                        samplerate=samplerate, 
324                        hopsize=self.params.hopsize, 
325                        outplot=options.outplot)
326
327
328class taskonset(task):
329        def __init__(self,input,output=None,params=None):
330                """ open the input file and initialize arguments
331                parameters should be set *before* calling this method.
332                """
333                task.__init__(self,input,params=params)
334                self.opick = onsetpick(self.params.bufsize,
335                        self.params.hopsize,
336                        self.channels,
337                        self.myvec,
338                        self.params.threshold,
339                        mode=get_onset_mode(self.params.onsetmode),
340                        derivate=self.params.derivate)
341                self.olist = [] 
342                self.ofunc = []
343                self.d,self.d2 = [],[]
344                self.maxofunc = 0
345                if self.params.localmin:
346                        self.ovalist   = [0., 0., 0., 0., 0.]
347
348        def __call__(self):
349                task.__call__(self)
350                isonset,val = self.opick.do(self.myvec)
351                if (aubio_silence_detection(self.myvec(),self.params.silence)):
352                        isonset=0
353                if self.params.storefunc:
354                        self.ofunc.append(val)
355                if self.params.localmin:
356                        if val > 0: self.ovalist.append(val)
357                        else: self.ovalist.append(0)
358                        self.ovalist.pop(0)
359                if (isonset == 1):
360                        if self.params.localmin:
361                                i=len(self.ovalist)-1
362                                # find local minima before peak
363                                while self.ovalist[i-1] < self.ovalist[i] and i > 0:
364                                        i -= 1
365                                now = (self.frameread+1-i)
366                        else:
367                                now = self.frameread
368                        if now < 0 :
369                                now = 0
370                        return now, val
371
372        def gettruth(self):
373                from os.path import isfile
374                ftru = '.'.join(self.input.split('.')[:-1])
375                ftru = '.'.join((ftru,'txt'))
376                if isfile(ftru): return ftru
377                else:            return
378
379        def eval(self,lres):
380                from txtfile import read_datafile
381                from onsetcompare import onset_roc
382                amode = 'roc'
383                vmode = 'verbose'
384                vmode = ''
385                ftru = self.gettruth()
386                if not ftru:
387                        print "ERR: no truth file found"
388                        return
389                ltru = read_datafile(ftru,depth=0)
390                for i in range(len(lres)): lres[i] = lres[i][0]*self.params.step
391                if vmode=='verbose':
392                        print "Running with mode %s" % self.params.mode, 
393                        print " and threshold %f" % self.params.threshold, 
394                        print " on file", input
395                #print ltru; print lres
396                if amode == 'localisation':
397                        l = onset_diffs(ltru,lres,self.params.tol)
398                        mean = 0
399                        for i in l: mean += i
400                        if len(l): print "%.3f" % (mean/len(l))
401                        else: print "?0"
402                elif amode == 'roc':
403                        self.orig, self.missed, self.merged, \
404                                self.expc, self.bad, self.doubled = \
405                                onset_roc(ltru,lres,self.params.tol)
406
407        def plot(self,onsets,ofunc):
408                import Gnuplot, Gnuplot.funcutils
409                import aubio.txtfile
410                import os.path
411                import numarray
412                from aubio.onsetcompare import onset_roc
413
414                self.lenofunc = len(ofunc) 
415                self.maxofunc = max(max(ofunc), self.maxofunc)
416                # onset detection function
417                downtime = numarray.arange(len(ofunc))/self.step
418                self.d.append(Gnuplot.Data(downtime,ofunc,with='lines'))
419
420                # detected onsets
421                x1 = numarray.array(onsets)/self.step
422                y1 = self.maxofunc*numarray.ones(len(onsets))
423                self.d.append(Gnuplot.Data(x1,y1,with='impulses'))
424                self.d2.append(Gnuplot.Data(x1,-y1,with='impulses'))
425
426                # check if datafile exists truth
427                datafile = self.input.replace('.wav','.txt')
428                if datafile == self.input: datafile = ""
429                if not os.path.isfile(datafile):
430                        self.title = "truth file not found"
431                        t = Gnuplot.Data(0,0,with='impulses') 
432                else:
433                        t_onsets = aubio.txtfile.read_datafile(datafile)
434                        y2 = self.maxofunc*numarray.ones(len(t_onsets))
435                        x2 = numarray.array(t_onsets).resize(len(t_onsets))
436                        self.d2.append(Gnuplot.Data(x2,y2,with='impulses'))
437                       
438                        tol = 0.050 
439
440                        orig, missed, merged, expc, bad, doubled = \
441                                onset_roc(x2,x1,tol)
442                        self.title = "GD %2.3f%% FP %2.3f%%" % \
443                                ((100*float(orig-missed-merged)/(orig)),
444                                 (100*float(bad+doubled)/(orig)))
445
446
447        def plotplot(self,outplot=None):
448                from aubio.gnuplot import gnuplot_init, audio_to_array, make_audio_plot
449                import re
450                # audio data
451                time,data = audio_to_array(self.input)
452                self.d2.append(make_audio_plot(time,data))
453                # prepare the plot
454                g = gnuplot_init(outplot)
455
456                g('set title \'%s %s\'' % (re.sub('.*/','',self.input),self.title))
457
458                g('set multiplot')
459
460                # hack to align left axis
461                g('set lmargin 15')
462
463                # plot waveform and onsets
464                g('set size 1,0.3')
465                g('set origin 0,0.7')
466                g('set xrange [0:%f]' % max(time)) 
467                g('set yrange [-1:1]') 
468                g.ylabel('amplitude')
469                g.plot(*self.d2)
470               
471                g('unset title')
472
473                # plot onset detection function
474                g('set size 1,0.7')
475                g('set origin 0,0')
476                g('set xrange [0:%f]' % (self.lenofunc/self.step))
477                g('set yrange [0:%f]' % (self.maxofunc*1.01))
478                g.xlabel('time')
479                g.ylabel('onset detection value')
480                g.plot(*self.d)
481
482                g('unset multiplot')
483
484class taskcut(task):
485        def __init__(self,input,slicetimes,params=None,output=None):
486                """ open the input file and initialize arguments
487                parameters should be set *before* calling this method.
488                """
489                task.__init__(self,input,output=None,params=params)
490                self.newname   = "%s%s%09.5f%s%s" % (self.input.split(".")[0].split("/")[-1],".",
491                                        self.frameread/self.step,".",self.input.split(".")[-1])
492                self.fileo       = sndfile(self.newname,model=self.filei)
493                self.myvec       = fvec(self.params.hopsize,self.channels)
494                self.mycopy     = fvec(self.params.hopsize,self.channels)
495                self.slicetimes = slicetimes
496
497        def __call__(self):
498                task.__call__(self)
499                # write to current file
500                if len(self.slicetimes) and self.frameread >= self.slicetimes[0]:
501                        self.slicetimes.pop(0)
502                        # write up to 1st zero crossing
503                        zerocross = 0
504                        while ( abs( self.myvec.get(zerocross,0) ) > self.params.zerothres ):
505                                zerocross += 1
506                        writesize = self.fileo.write(zerocross,self.myvec)
507                        fromcross = 0
508                        while (zerocross < self.readsize):
509                                for i in range(self.channels):
510                                        self.mycopy.set(self.myvec.get(zerocross,i),fromcross,i)
511                                        fromcross += 1
512                                        zerocross += 1
513                        del self.fileo
514                        self.fileo = sndfile("%s%s%09.5f%s%s" % 
515                                (self.input.split(".")[0].split("/")[-1],".",
516                                self.frameread/self.step,".",self.input.split(".")[-1]),model=self.filei)
517                        writesize = self.fileo.write(fromcross,self.mycopy)
518                else:
519                        writesize = self.fileo.write(self.readsize,self.myvec)
520
521class taskbeat(taskonset):
522        def __init__(self,input,params=None,output=None):
523                """ open the input file and initialize arguments
524                parameters should be set *before* calling this method.
525                """
526                taskonset.__init__(self,input,output=None,params=params)
527                self.btwinlen  = 512**2/self.params.hopsize
528                self.btstep    = self.btwinlen/4
529                self.btoutput  = fvec(self.btstep,self.channels)
530                self.dfframe   = fvec(self.btwinlen,self.channels)
531                self.bt        = beattracking(self.btwinlen,self.channels)
532                self.pos2      = 0
533
534        def __call__(self):
535                taskonset.__call__(self)
536                # write to current file
537                if self.pos2 == self.btstep - 1 : 
538                        self.bt.do(self.dfframe,self.btoutput)
539                        for i in range (self.btwinlen - self.btstep):
540                                self.dfframe.set(self.dfframe.get(i+self.btstep,0),i,0) 
541                        for i in range(self.btwinlen - self.btstep, self.btwinlen): 
542                                self.dfframe.set(0,i,0)
543                        self.pos2 = -1;
544                self.pos2 += 1
545                val = self.opick.pp.getval()
546                self.dfframe.set(val,self.btwinlen - self.btstep + self.pos2,0)
547                i=0
548                for i in range(1,int( self.btoutput.get(0,0) ) ):
549                        if self.pos2 == self.btoutput.get(i,0) and \
550                                aubio_silence_detection(self.myvec(),
551                                        self.params.silence)!=1: 
552                                return self.frameread, 0 
553       
554        def eval(self,results):
555                pass
Note: See TracBrowser for help on using the repository browser.