fazekasgy@37: '''PyZeroCrossing.py - Example plugin demonstrates fazekasgy@37: how to write a Vampy plugin in pure Python without fazekasgy@37: using Numpy or the extensions provided by the embedded fazekasgy@37: vampy module. fazekasgy@37: fazekasgy@37: This plugin is compatible with provious versions of vampy, fazekasgy@37: apart from moving the inputSampleRate fazekasgy@37: argument from initialise to __init__() fazekasgy@37: fazekasgy@37: Outputs: fazekasgy@37: 1) Zero crossing counts fazekasgy@37: 2) Zero crossing locations fazekasgy@37: fazekasgy@37: Centre for Digital Music, Queen Mary University of London. fazekasgy@37: Copyright (C) 2009 Gyorgy Fazekas, QMUL. (See Vamp sources fazekasgy@37: for licence information.) fazekasgy@37: fazekasgy@37: ''' fazekasgy@37: fazekasgy@37: class PyZeroCrossing: fazekasgy@37: fazekasgy@37: def __init__(self,inputSampleRate): fazekasgy@37: self.m_inputSampleRate = inputSampleRate fazekasgy@37: self.m_stepSize = 0 fazekasgy@37: self.m_blockSize = 0 fazekasgy@37: self.m_channels = 0 fazekasgy@37: self.previousSample = 0.0 fazekasgy@37: self.threshold = 0.005 fazekasgy@37: self.counter = 0 fazekasgy@37: fazekasgy@37: def initialise(self,channels,stepSize,blockSize): fazekasgy@37: self.m_channels = channels fazekasgy@37: self.m_stepSize = stepSize fazekasgy@37: self.m_blockSize = blockSize fazekasgy@37: return True fazekasgy@37: fazekasgy@37: def getMaker(self): fazekasgy@37: return 'Vampy Example Plugins' fazekasgy@37: fazekasgy@37: def getName(self): fazekasgy@37: return 'Vampy Zero Crossings' Chris@69: Chris@69: def getDescription(self): Chris@69: return 'Count the number of simple zero-crossings for the signal within each processing block' Chris@69: Chris@69: def getCopyright(self): Chris@69: return 'Plugin By George Fazekas. Freely redistributable example plugin (BSD license)' fazekasgy@37: fazekasgy@37: def getIdentifier(self): fazekasgy@37: return 'vampy-zc2' fazekasgy@37: fazekasgy@37: def getMaxChannelCount(self): fazekasgy@37: return 1 fazekasgy@37: fazekasgy@37: def getInputDomain(self): fazekasgy@37: return 'TimeDomain' fazekasgy@37: fazekasgy@37: def getOutputDescriptors(self): fazekasgy@37: fazekasgy@37: #descriptors can be returned as python dictionaries fazekasgy@37: output0={ fazekasgy@37: 'identifier':'vampy-counts', fazekasgy@37: 'name':'Number of Zero Crossings', fazekasgy@37: 'description':'Number of zero crossings per audio frame', fazekasgy@37: 'unit':' ', fazekasgy@37: 'hasFixedBinCount':True, fazekasgy@37: 'binCount':1, fazekasgy@37: #'binNames':['1 Hz',1.5,'2 Hz',3,'4 Hz'], fazekasgy@37: 'hasKnownExtents':False, fazekasgy@37: #'minValue':0.0, fazekasgy@37: #'maxValue':0.0, fazekasgy@37: 'isQuantized':True, fazekasgy@37: 'quantizeStep':1.0, fazekasgy@37: 'sampleType':'OneSamplePerStep' fazekasgy@37: #'sampleRate':48000.0 fazekasgy@37: } fazekasgy@37: fazekasgy@37: output1={ fazekasgy@37: 'identifier':'vampy-crossings', fazekasgy@37: 'name':'Zero Crossing Locations', fazekasgy@37: 'description':'The locations of zero crossing points', fazekasgy@37: 'unit':'discrete', fazekasgy@37: 'hasFixedBinCount':True, fazekasgy@37: 'binCount':0, fazekasgy@37: 'sampleType':'VariableSampleRate' fazekasgy@37: } fazekasgy@37: fazekasgy@37: return [output0,output1] fazekasgy@37: fazekasgy@37: fazekasgy@37: def getParameterDescriptors(self): fazekasgy@37: paramlist1={ fazekasgy@37: 'identifier':'threshold', fazekasgy@37: 'name':'Noise threshold', Chris@68: 'description':'Magnitude below which a process block will be considered to be all zero', fazekasgy@37: 'unit':'v', fazekasgy@37: 'minValue':0.0, fazekasgy@37: 'maxValue':0.5, fazekasgy@37: 'defaultValue':0.005, fazekasgy@37: 'isQuantized':False fazekasgy@37: } fazekasgy@37: return [paramlist1] fazekasgy@37: fazekasgy@37: fazekasgy@37: def setParameter(self,paramid,newval): fazekasgy@37: if paramid == 'threshold' : fazekasgy@37: self.threshold = newval fazekasgy@37: return fazekasgy@37: fazekasgy@37: fazekasgy@37: def getParameter(self,paramid): fazekasgy@37: if paramid == 'threshold' : fazekasgy@37: return self.threshold fazekasgy@37: else: fazekasgy@37: return 0.0 fazekasgy@37: fazekasgy@37: fazekasgy@37: # legacy process type: the input is a python list of samples fazekasgy@37: def process(self,inbuf,timestamp): fazekasgy@37: crossing = False fazekasgy@37: prev = self.previousSample fazekasgy@37: count = 0.0; fazekasgy@37: channel = inbuf[0] fazekasgy@37: fazekasgy@37: #we have two outputs defined thus we have to declare fazekasgy@37: #them as empty dictionaries in our output list fazekasgy@37: #in order to be able to return variable rate outputs fazekasgy@37: output0=[] fazekasgy@37: output1=[] fazekasgy@37: fazekasgy@37: if sum([abs(s) for s in channel]) > self.threshold : fazekasgy@37: fazekasgy@37: for x in range(len(channel)-1) : fazekasgy@37: crossing = False fazekasgy@37: sample = channel[x] fazekasgy@37: if sample <= 0.0 : fazekasgy@37: if prev > 0.0 : crossing = True fazekasgy@37: else : fazekasgy@37: if sample > 0.0 : fazekasgy@37: if prev <= 0.0 : crossing = True fazekasgy@37: fazekasgy@37: if crossing == True : fazekasgy@37: count = count + 1 fazekasgy@37: feature1={ fazekasgy@37: 'hasTimestamp':True, fazekasgy@37: 'timeStamp':long(timestamp + x), fazekasgy@37: 'values':[count], fazekasgy@37: 'label':str(count), fazekasgy@37: } fazekasgy@37: output1.append(feature1) fazekasgy@37: fazekasgy@37: prev = sample fazekasgy@37: self.previousSample = prev fazekasgy@37: fazekasgy@37: else : fazekasgy@37: count = 0.0 fazekasgy@37: self.previousSample = channel[len(channel)-1] fazekasgy@37: fazekasgy@37: feature0={ fazekasgy@37: 'hasTimestamp':False, fazekasgy@37: 'values':[count], fazekasgy@37: 'label':str(count) fazekasgy@37: } fazekasgy@37: output0.append(feature0) fazekasgy@37: fazekasgy@37: #return a LIST of list of dictionaries fazekasgy@37: return [output0,output1] fazekasgy@37: