fazekasgy@9: '''PySpectralFeatures.py - Example plugin demonstrates''' fazekasgy@9: '''how to use the NumPy array interface and write Matlab style code.''' fazekasgy@9: fazekasgy@9: from numpy import * fazekasgy@9: fazekasgy@9: class PySpectralFeatures: fazekasgy@9: fazekasgy@9: def __init__(self): fazekasgy@9: self.m_imputSampleRate = 0.0 fazekasgy@9: self.m_stepSize = 0 fazekasgy@9: self.m_blockSize = 0 fazekasgy@9: self.m_channels = 0 fazekasgy@9: self.threshold = 0.00 fazekasgy@9: self.r = 2.0 fazekasgy@9: fazekasgy@9: def initialise(self,channels,stepSize,blockSize,inputSampleRate): fazekasgy@9: self.m_channels = channels fazekasgy@9: self.m_stepSize = stepSize fazekasgy@9: self.m_blockSize = blockSize fazekasgy@9: self.m_inputSampleRate = inputSampleRate fazekasgy@9: #self.prevMag = ones((blockSize/2)-1) / ((blockSize/2)-1) fazekasgy@9: self.prevMag = zeros((blockSize/2)-1) fazekasgy@9: self.prevMag[0] = 1 fazekasgy@9: fazekasgy@9: return True fazekasgy@9: fazekasgy@9: def getMaker(self): fazekasgy@9: return 'VamPy Example Plugins' fazekasgy@9: fazekasgy@9: def getName(self): fazekasgy@9: return 'VamPy Spectral Features' fazekasgy@9: fazekasgy@9: def getIdentifier(self): fazekasgy@9: return 'vampy-sf2' fazekasgy@9: fazekasgy@9: def getDescription(self): fazekasgy@9: return 'A collection of low-level spectral descriptors.' fazekasgy@9: fazekasgy@9: def getMaxChannelCount(self): fazekasgy@9: return 1 fazekasgy@9: fazekasgy@9: def getInputDomain(self): fazekasgy@9: return 'FrequencyDomain' fazekasgy@9: fazekasgy@9: def getOutputDescriptors(self): fazekasgy@9: fazekasgy@9: #descriptors are python dictionaries fazekasgy@9: #Generic values are the same for all fazekasgy@9: Generic={ fazekasgy@9: 'hasFixedBinCount':True, fazekasgy@9: 'binCount':1, fazekasgy@9: 'hasKnownExtents':False, fazekasgy@9: 'isQuantized':False, fazekasgy@9: 'sampleType':'OneSamplePerStep' fazekasgy@9: } fazekasgy@9: fazekasgy@9: #Spectral centroid etc... fazekasgy@9: SC=Generic.copy() fazekasgy@9: SC.update({ fazekasgy@9: 'identifier':'vampy-sc', fazekasgy@9: 'name':'Spectral Centroid', fazekasgy@9: 'description':'Spectral Centroid (Brightness)', fazekasgy@9: 'unit':'Hz' fazekasgy@9: }) fazekasgy@9: fazekasgy@9: SCF=Generic.copy() fazekasgy@9: SCF.update({ fazekasgy@9: 'identifier':'vampy-scf', fazekasgy@9: 'name':'Spectral Crest Factor', fazekasgy@9: 'description':'Spectral Crest (Tonality)', fazekasgy@9: 'unit':'v' fazekasgy@9: }) fazekasgy@9: fazekasgy@9: BW=Generic.copy() fazekasgy@9: BW.update({ fazekasgy@9: 'identifier':'vampy-bw', fazekasgy@9: 'name':'Band Width', fazekasgy@9: 'description':'Spectral Band Width', fazekasgy@9: 'unit':'Hz', fazekasgy@9: }) fazekasgy@9: fazekasgy@9: SE=Generic.copy() fazekasgy@9: SE.update({ fazekasgy@9: 'identifier':'vampy-se', fazekasgy@9: 'name':'Shannon Entropy', fazekasgy@9: 'description':'Shannon Entropy', fazekasgy@9: 'unit':'', fazekasgy@9: }) fazekasgy@9: fazekasgy@9: RE=Generic.copy() fazekasgy@9: RE.update({ fazekasgy@9: 'identifier':'vampy-re', fazekasgy@9: 'name':'Renyi Entropy', fazekasgy@9: 'description':'Renyi Entropy', fazekasgy@9: 'unit':'', fazekasgy@9: }) fazekasgy@9: fazekasgy@9: KL=Generic.copy() fazekasgy@9: KL.update({ fazekasgy@9: 'identifier':'vampy-kl', fazekasgy@9: 'name':'Kullback Leibler divergence', fazekasgy@9: 'description':'KL divergence between successive spectra', fazekasgy@9: 'unit':'', fazekasgy@9: }) fazekasgy@9: fazekasgy@9: #return a list of dictionaries fazekasgy@9: return [SC,SCF,BW,SE,RE,KL] fazekasgy@9: fazekasgy@9: def getParameterDescriptors(self): fazekasgy@9: threshold={ fazekasgy@9: 'identifier':'threshold', fazekasgy@9: 'name':'Noise threshold: ', fazekasgy@9: 'description':'', fazekasgy@9: 'unit':'v', fazekasgy@9: 'minValue':0.0, fazekasgy@9: 'maxValue':0.5, fazekasgy@9: 'defaultValue':0.05, fazekasgy@9: 'isQuantized':False fazekasgy@9: } fazekasgy@9: fazekasgy@9: renyicoeff={ fazekasgy@9: 'identifier':'r', fazekasgy@9: 'name':'Renyi entropy coeff: ', fazekasgy@9: 'description':'', fazekasgy@9: 'unit':'', fazekasgy@9: 'minValue':0.0, fazekasgy@9: 'maxValue':10.0, fazekasgy@9: 'defaultValue':2, fazekasgy@9: 'isQuantized':False fazekasgy@9: } fazekasgy@9: fazekasgy@9: return [threshold,renyicoeff] fazekasgy@9: fazekasgy@9: def setParameter(self,paramid,newval): fazekasgy@9: if paramid == 'threshold' : fazekasgy@9: self.threshold = newval fazekasgy@9: if paramid == 'r' : fazekasgy@9: self.r == newval fazekasgy@9: return fazekasgy@9: fazekasgy@9: def getParameter(self,paramid): fazekasgy@9: if paramid == 'threshold' : fazekasgy@9: return self.threshold fazekasgy@9: if paramid == 'r': fazekasgy@9: return float(self.r) fazekasgy@9: else: fazekasgy@9: return 0.0 fazekasgy@9: fazekasgy@9: def processN(self,membuffer,samplecount): fazekasgy@9: fftsize = self.m_blockSize fazekasgy@9: sampleRate = self.m_inputSampleRate fazekasgy@9: fazekasgy@9: #for time domain plugins use the following line: fazekasgy@9: #audioSamples = frombuffer(membuffer[0],float32) fazekasgy@9: #-1: do till the end, skip DC 2*32bit / 8bit = 8byte fazekasgy@9: complexSpectrum = frombuffer(membuffer[0],complex64,-1,8) fazekasgy@9: magnitudeSpectrum = abs(complexSpectrum) / (fftsize/2) fazekasgy@9: tpower = sum(magnitudeSpectrum) fazekasgy@9: #phaseSpectrum = angle(complexSpectrum) fazekasgy@9: fazekasgy@9: freq = array(range(1,len(complexSpectrum)+1)) \ fazekasgy@9: * sampleRate / fftsize fazekasgy@9: fazekasgy@9: centroid = 0.0 fazekasgy@9: crest = 0.0 fazekasgy@9: bw = 0.0 fazekasgy@9: shannon = 0.0 fazekasgy@9: renyi = 0.0 fazekasgy@9: r = self.r fazekasgy@9: KLdiv = 0.0 fazekasgy@9: flatness = 0.0 fazekasgy@9: exp=1.0 / (fftsize/2) fazekasgy@9: #print exp fazekasgy@9: fazekasgy@9: #declare outputs fazekasgy@9: output0=[] fazekasgy@9: output1=[] fazekasgy@9: output2=[] fazekasgy@9: output3=[] fazekasgy@9: output4=[] fazekasgy@9: output5=[] fazekasgy@9: fazekasgy@9: if tpower > self.threshold : fazekasgy@9: fazekasgy@9: centroid = sum(freq * magnitudeSpectrum) / tpower fazekasgy@9: crest = max(magnitudeSpectrum) / tpower fazekasgy@9: bw = sum( abs(freq - centroid) * magnitudeSpectrum ) / tpower fazekasgy@9: #flatness = prod(abs(complexSpectrum)) fazekasgy@9: #print flatness fazekasgy@9: normMag = magnitudeSpectrum / tpower #make it sum to 1 fazekasgy@9: shannon = - sum( normMag * log2(normMag) ) fazekasgy@9: renyi = (1/1-r) * log10( sum( power(normMag,r))) fazekasgy@9: KLdiv = sum( normMag * log2(normMag / self.prevMag) ) fazekasgy@9: self.prevMag = normMag fazekasgy@9: fazekasgy@9: output0.append({ fazekasgy@9: 'hasTimestamp':False, fazekasgy@9: 'values':[float(centroid)], fazekasgy@9: #'label':str(centroid) fazekasgy@9: }) fazekasgy@9: fazekasgy@9: output1.append({ fazekasgy@9: 'hasTimestamp':False, fazekasgy@9: 'values':[float(crest)], fazekasgy@9: #'label':str(crest) fazekasgy@9: }) fazekasgy@9: fazekasgy@9: output2.append({ fazekasgy@9: 'hasTimestamp':False, fazekasgy@9: 'values':[float(bw)], fazekasgy@9: #'label':str(bw) fazekasgy@9: }) fazekasgy@9: fazekasgy@9: output3.append({ fazekasgy@9: 'hasTimestamp':False, fazekasgy@9: 'values':[float(shannon)], fazekasgy@9: #'label':str(shannon) fazekasgy@9: }) fazekasgy@9: fazekasgy@9: output4.append({ fazekasgy@9: 'hasTimestamp':False, fazekasgy@9: 'values':[float(renyi)], fazekasgy@9: #'label':str(renyi) fazekasgy@9: }) fazekasgy@9: fazekasgy@9: output5.append({ fazekasgy@9: 'hasTimestamp':False, fazekasgy@9: 'values':[float(KLdiv)], #strictly must be a list fazekasgy@9: #'label':str(renyi) fazekasgy@9: }) fazekasgy@9: fazekasgy@9: #return a LIST of list of dictionaries fazekasgy@9: return [output0,output1,output2,output3,output4,output5]