annotate Example VamPy plugins/PySpectralFeatures.py @ 30:6dda7feaac1f vampy1

* Move trunk to vampy1 branch (preparing to bring vampy2 to trunk)
author cannam
date Mon, 05 Oct 2009 12:47:01 +0000
parents ba3686eb697c
children
rev   line source
fazekasgy@9 1 '''PySpectralFeatures.py - Example plugin demonstrates'''
fazekasgy@9 2 '''how to use the NumPy array interface and write Matlab style code.'''
fazekasgy@9 3
fazekasgy@9 4 from numpy import *
fazekasgy@9 5
fazekasgy@9 6 class PySpectralFeatures:
fazekasgy@9 7
cannam@24 8 def __init__(self,inputSampleRate):
cannam@24 9 self.m_inputSampleRate = inputSampleRate
fazekasgy@9 10 self.m_stepSize = 0
fazekasgy@9 11 self.m_blockSize = 0
fazekasgy@9 12 self.m_channels = 0
fazekasgy@26 13 self.threshold = 0.05
fazekasgy@9 14 self.r = 2.0
fazekasgy@26 15 return None
fazekasgy@9 16
cannam@24 17 def initialise(self,channels,stepSize,blockSize):
fazekasgy@9 18 self.m_channels = channels
fazekasgy@9 19 self.m_stepSize = stepSize
fazekasgy@9 20 self.m_blockSize = blockSize
fazekasgy@9 21 self.prevMag = zeros((blockSize/2)-1)
fazekasgy@9 22 self.prevMag[0] = 1
fazekasgy@9 23 return True
fazekasgy@26 24
fazekasgy@26 25 def reset(self):
fazekasgy@26 26 # reset any initial conditions
fazekasgy@26 27 self.prevMag = zeros((self.m_blockSize/2)-1)
fazekasgy@26 28 self.prevMag[0] = 1
fazekasgy@26 29 return None
fazekasgy@9 30
fazekasgy@9 31 def getMaker(self):
fazekasgy@9 32 return 'VamPy Example Plugins'
fazekasgy@9 33
fazekasgy@9 34 def getName(self):
fazekasgy@9 35 return 'VamPy Spectral Features'
fazekasgy@9 36
fazekasgy@9 37 def getIdentifier(self):
fazekasgy@9 38 return 'vampy-sf2'
fazekasgy@9 39
fazekasgy@9 40 def getDescription(self):
fazekasgy@9 41 return 'A collection of low-level spectral descriptors.'
fazekasgy@9 42
fazekasgy@9 43 def getMaxChannelCount(self):
fazekasgy@9 44 return 1
fazekasgy@9 45
fazekasgy@9 46 def getInputDomain(self):
fazekasgy@9 47 return 'FrequencyDomain'
fazekasgy@9 48
fazekasgy@9 49 def getOutputDescriptors(self):
fazekasgy@9 50
fazekasgy@9 51 #descriptors are python dictionaries
fazekasgy@9 52 #Generic values are the same for all
fazekasgy@9 53 Generic={
fazekasgy@9 54 'hasFixedBinCount':True,
fazekasgy@9 55 'binCount':1,
fazekasgy@9 56 'hasKnownExtents':False,
fazekasgy@9 57 'isQuantized':False,
fazekasgy@9 58 'sampleType':'OneSamplePerStep'
fazekasgy@9 59 }
fazekasgy@9 60
fazekasgy@9 61 #Spectral centroid etc...
fazekasgy@9 62 SC=Generic.copy()
fazekasgy@9 63 SC.update({
fazekasgy@9 64 'identifier':'vampy-sc',
fazekasgy@9 65 'name':'Spectral Centroid',
fazekasgy@9 66 'description':'Spectral Centroid (Brightness)',
fazekasgy@9 67 'unit':'Hz'
fazekasgy@9 68 })
fazekasgy@9 69
fazekasgy@9 70 SCF=Generic.copy()
fazekasgy@9 71 SCF.update({
fazekasgy@9 72 'identifier':'vampy-scf',
fazekasgy@9 73 'name':'Spectral Crest Factor',
fazekasgy@9 74 'description':'Spectral Crest (Tonality)',
fazekasgy@9 75 'unit':'v'
fazekasgy@9 76 })
fazekasgy@9 77
fazekasgy@9 78 BW=Generic.copy()
fazekasgy@9 79 BW.update({
fazekasgy@9 80 'identifier':'vampy-bw',
fazekasgy@9 81 'name':'Band Width',
fazekasgy@9 82 'description':'Spectral Band Width',
fazekasgy@9 83 'unit':'Hz',
fazekasgy@9 84 })
fazekasgy@9 85
fazekasgy@9 86 SE=Generic.copy()
fazekasgy@9 87 SE.update({
fazekasgy@9 88 'identifier':'vampy-se',
fazekasgy@9 89 'name':'Shannon Entropy',
fazekasgy@9 90 'description':'Shannon Entropy',
fazekasgy@9 91 'unit':'',
fazekasgy@9 92 })
fazekasgy@9 93
fazekasgy@9 94 RE=Generic.copy()
fazekasgy@9 95 RE.update({
fazekasgy@9 96 'identifier':'vampy-re',
fazekasgy@9 97 'name':'Renyi Entropy',
fazekasgy@9 98 'description':'Renyi Entropy',
fazekasgy@9 99 'unit':'',
fazekasgy@9 100 })
fazekasgy@9 101
fazekasgy@9 102 KL=Generic.copy()
fazekasgy@9 103 KL.update({
fazekasgy@9 104 'identifier':'vampy-kl',
fazekasgy@9 105 'name':'Kullback Leibler divergence',
fazekasgy@9 106 'description':'KL divergence between successive spectra',
fazekasgy@9 107 'unit':'',
fazekasgy@9 108 })
fazekasgy@9 109
fazekasgy@9 110 #return a list of dictionaries
fazekasgy@9 111 return [SC,SCF,BW,SE,RE,KL]
fazekasgy@9 112
fazekasgy@9 113 def getParameterDescriptors(self):
fazekasgy@9 114 threshold={
fazekasgy@9 115 'identifier':'threshold',
fazekasgy@9 116 'name':'Noise threshold: ',
fazekasgy@26 117 'description':'Noise threshold',
fazekasgy@9 118 'unit':'v',
fazekasgy@9 119 'minValue':0.0,
fazekasgy@9 120 'maxValue':0.5,
fazekasgy@9 121 'defaultValue':0.05,
fazekasgy@9 122 'isQuantized':False
fazekasgy@9 123 }
fazekasgy@9 124
fazekasgy@9 125 renyicoeff={
fazekasgy@9 126 'identifier':'r',
fazekasgy@9 127 'name':'Renyi entropy coeff: ',
fazekasgy@26 128 'description':'Renyi entropy coeff',
fazekasgy@9 129 'unit':'',
fazekasgy@9 130 'minValue':0.0,
fazekasgy@9 131 'maxValue':10.0,
fazekasgy@26 132 'defaultValue':2.0,
fazekasgy@9 133 'isQuantized':False
fazekasgy@9 134 }
fazekasgy@9 135
fazekasgy@9 136 return [threshold,renyicoeff]
fazekasgy@9 137
fazekasgy@9 138 def setParameter(self,paramid,newval):
fazekasgy@9 139 if paramid == 'threshold' :
fazekasgy@9 140 self.threshold = newval
fazekasgy@9 141 if paramid == 'r' :
fazekasgy@9 142 self.r == newval
fazekasgy@9 143 return
fazekasgy@9 144
fazekasgy@9 145 def getParameter(self,paramid):
fazekasgy@9 146 if paramid == 'threshold' :
fazekasgy@9 147 return self.threshold
fazekasgy@9 148 if paramid == 'r':
fazekasgy@9 149 return float(self.r)
fazekasgy@9 150 else:
fazekasgy@9 151 return 0.0
fazekasgy@9 152
fazekasgy@9 153 def processN(self,membuffer,samplecount):
fazekasgy@9 154 fftsize = self.m_blockSize
fazekasgy@9 155 sampleRate = self.m_inputSampleRate
fazekasgy@9 156
fazekasgy@9 157 #for time domain plugins use the following line:
fazekasgy@9 158 #audioSamples = frombuffer(membuffer[0],float32)
fazekasgy@26 159 #for frequency domain plugins use the following line:
fazekasgy@9 160 complexSpectrum = frombuffer(membuffer[0],complex64,-1,8)
fazekasgy@26 161 #meaning of the parameters above:
fazekasgy@26 162 #-1: do until the end, skip DC 2*32bit / 8bit = 8byte
fazekasgy@9 163 magnitudeSpectrum = abs(complexSpectrum) / (fftsize/2)
fazekasgy@9 164 tpower = sum(magnitudeSpectrum)
fazekasgy@9 165 #phaseSpectrum = angle(complexSpectrum)
fazekasgy@9 166
fazekasgy@9 167 freq = array(range(1,len(complexSpectrum)+1)) \
fazekasgy@9 168 * sampleRate / fftsize
fazekasgy@9 169
fazekasgy@9 170 centroid = 0.0
fazekasgy@9 171 crest = 0.0
fazekasgy@9 172 bw = 0.0
fazekasgy@9 173 shannon = 0.0
fazekasgy@9 174 renyi = 0.0
fazekasgy@9 175 KLdiv = 0.0
fazekasgy@9 176 exp=1.0 / (fftsize/2)
fazekasgy@9 177
fazekasgy@9 178 #declare outputs
fazekasgy@9 179 output0=[]
fazekasgy@9 180 output1=[]
fazekasgy@9 181 output2=[]
fazekasgy@9 182 output3=[]
fazekasgy@9 183 output4=[]
fazekasgy@9 184 output5=[]
fazekasgy@9 185
fazekasgy@9 186 if tpower > self.threshold :
fazekasgy@9 187
fazekasgy@9 188 centroid = sum(freq * magnitudeSpectrum) / tpower
fazekasgy@9 189 crest = max(magnitudeSpectrum) / tpower
fazekasgy@9 190 bw = sum( abs(freq - centroid) * magnitudeSpectrum ) / tpower
fazekasgy@9 191 normMag = magnitudeSpectrum / tpower #make it sum to 1
fazekasgy@9 192 shannon = - sum( normMag * log2(normMag) )
fazekasgy@26 193 renyi = (1/1-self.r) * log10( sum( power(normMag,self.r)))
fazekasgy@9 194 KLdiv = sum( normMag * log2(normMag / self.prevMag) )
fazekasgy@9 195 self.prevMag = normMag
fazekasgy@9 196
fazekasgy@9 197 output0.append({
fazekasgy@9 198 'hasTimestamp':False,
fazekasgy@9 199 'values':[float(centroid)],
fazekasgy@9 200 #'label':str(centroid)
fazekasgy@9 201 })
fazekasgy@9 202
fazekasgy@9 203 output1.append({
fazekasgy@9 204 'hasTimestamp':False,
fazekasgy@9 205 'values':[float(crest)],
fazekasgy@9 206 #'label':str(crest)
fazekasgy@9 207 })
fazekasgy@9 208
fazekasgy@9 209 output2.append({
fazekasgy@9 210 'hasTimestamp':False,
fazekasgy@9 211 'values':[float(bw)],
fazekasgy@9 212 #'label':str(bw)
fazekasgy@9 213 })
fazekasgy@9 214
fazekasgy@9 215 output3.append({
fazekasgy@9 216 'hasTimestamp':False,
fazekasgy@9 217 'values':[float(shannon)],
fazekasgy@9 218 #'label':str(shannon)
fazekasgy@9 219 })
fazekasgy@9 220
fazekasgy@9 221 output4.append({
fazekasgy@9 222 'hasTimestamp':False,
fazekasgy@9 223 'values':[float(renyi)],
fazekasgy@9 224 #'label':str(renyi)
fazekasgy@9 225 })
fazekasgy@9 226
fazekasgy@9 227 output5.append({
fazekasgy@9 228 'hasTimestamp':False,
fazekasgy@9 229 'values':[float(KLdiv)], #strictly must be a list
fazekasgy@9 230 #'label':str(renyi)
fazekasgy@9 231 })
fazekasgy@9 232
fazekasgy@9 233 #return a LIST of list of dictionaries
fazekasgy@9 234 return [output0,output1,output2,output3,output4,output5]
fazekasgy@26 235