source: python/aubio/tasks.py @ 1e3089c

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

remove old plot_pitch, plot_onset and getonsets, cutfile, getpitch
remove old plot_pitch, plot_onset and getonsets, cutfile, getpitch

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