source: python/aubio/tasks.py @ 83c6734

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

add support for delay to task onset, invert silence output, remove unused import
add support for delay to task onset, invert silence output, remove unused import

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