source: python/aubio/tasks.py @ 37f0352

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

add mintol to taskonset, fix taskpitch.eval
add mintol to taskonset, fix taskpitch.eval

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