annotate Example VamPy plugins/PySpectralCentroid.py @ 68:44d56a3d16b7

Various fixes to the example plugins
author Chris Cannam
date Mon, 17 Nov 2014 11:44:15 +0000
parents d56f48aafb99
children f5b8646494d2
rev   line source
fazekasgy@52 1 '''PySpectralCentroid.py - Example plugin demonstrates
fazekasgy@52 2 how to write a C style plugin using VamPy in pure Python.
fazekasgy@52 3 This plugin also introduces the use of the builtin vampy
fazekasgy@52 4 extension module.
fazekasgy@52 5
fazekasgy@52 6 The plugin has frequency domain input and is using the
fazekasgy@52 7 legacy interface: the FFT outpout is passed as a list
fazekasgy@52 8 of complex numbers.
fazekasgy@52 9
fazekasgy@52 10 Outputs:
fazekasgy@52 11 1) Spectral centroid
fazekasgy@52 12
fazekasgy@52 13 Note: This is not the adviced way of writing Vampy plugins now,
fazekasgy@52 14 since the interfaces provided for Numpy are at least 5 times
fazekasgy@52 15 faster. However, this is still a nice and easy to understand
fazekasgy@52 16 example, which also shows how can one write a reasonable
fazekasgy@52 17 plugin without having Numpy installed.
fazekasgy@52 18
fazekasgy@52 19 Warning: Earlier versions of this plugin are now obsolete.
fazekasgy@52 20 (They were using the legacy interface of Vampy 1 which
fazekasgy@52 21 did not distinquish between time and frequency domain inputs.)
fazekasgy@52 22
fazekasgy@52 23 Centre for Digital Music, Queen Mary University of London.
fazekasgy@52 24 Copyright (C) 2009 Gyorgy Fazekas, QMUL. (See Vamp sources
fazekasgy@52 25 for licence information.)
fazekasgy@52 26
fazekasgy@52 27 '''
fazekasgy@52 28
fazekasgy@52 29 # import the names we use from vampy
fazekasgy@52 30 from vampy import Feature,FeatureSet,ParameterDescriptor
fazekasgy@52 31 from vampy import OutputDescriptor,FrequencyDomain,OneSamplePerStep
fazekasgy@52 32
fazekasgy@52 33 from math import sqrt
fazekasgy@52 34
fazekasgy@52 35 class PySpectralCentroid:
fazekasgy@52 36
fazekasgy@52 37 def __init__(self,inputSampleRate):
fazekasgy@52 38 self.m_imputSampleRate = 0.0
fazekasgy@52 39 self.m_stepSize = 0
fazekasgy@52 40 self.m_blockSize = 0
fazekasgy@52 41 self.m_channels = 0
fazekasgy@52 42 self.previousSample = 0.0
fazekasgy@52 43 self.m_inputSampleRate = inputSampleRate
Chris@68 44 self.threshold = 0.05
fazekasgy@52 45
fazekasgy@52 46 def initialise(self,channels,stepSize,blockSize):
fazekasgy@52 47 self.m_channels = channels
fazekasgy@52 48 self.m_stepSize = stepSize
fazekasgy@52 49 self.m_blockSize = blockSize
fazekasgy@52 50 return True
fazekasgy@52 51
fazekasgy@52 52 def getMaker(self):
fazekasgy@52 53 return 'Vampy Example Plugins'
fazekasgy@52 54
fazekasgy@52 55 def getName(self):
fazekasgy@52 56 return 'Spectral Centroid (using legacy process interface)'
fazekasgy@52 57
fazekasgy@52 58 def getIdentifier(self):
fazekasgy@52 59 return 'vampy-sc3'
fazekasgy@52 60
fazekasgy@52 61 def getMaxChannelCount(self):
fazekasgy@52 62 return 1
fazekasgy@52 63
fazekasgy@52 64 def getInputDomain(self):
fazekasgy@52 65 return FrequencyDomain
fazekasgy@52 66
fazekasgy@52 67 def getOutputDescriptors(self):
fazekasgy@52 68
fazekasgy@52 69 cod = OutputDescriptor()
fazekasgy@52 70 cod.identifier='vampy-sc3'
fazekasgy@52 71 cod.name='Spectral Centroid'
fazekasgy@52 72 cod.description='Spectral Centroid (Brightness)'
fazekasgy@52 73 cod.unit=''
fazekasgy@52 74 cod.hasFixedBinCount=True
fazekasgy@52 75 cod.binCount=1
fazekasgy@52 76 cod.hasKnownExtents=False
fazekasgy@52 77 cod.isQuantized=True
fazekasgy@52 78 cod.quantizeStep=1.0
fazekasgy@52 79 cod.sampleType=OneSamplePerStep
fazekasgy@52 80 return cod
fazekasgy@52 81
fazekasgy@52 82 def getParameterDescriptors(self):
fazekasgy@52 83 thd = ParameterDescriptor()
fazekasgy@52 84 thd.identifier='threshold'
fazekasgy@52 85 thd.name='Noise threshold'
Chris@68 86 thd.description='Magnitude below which a process block will be disregarded and zero returned'
fazekasgy@52 87 thd.unit='v'
fazekasgy@52 88 thd.minValue=0.0
fazekasgy@52 89 thd.maxValue=0.5
fazekasgy@52 90 thd.defaultValue=0.05
fazekasgy@52 91 thd.isQuantized=False
fazekasgy@52 92 return thd
fazekasgy@52 93
fazekasgy@52 94 def setParameter(self,paramid,newval):
fazekasgy@52 95 if paramid == 'threshold' :
fazekasgy@52 96 self.threshold = newval
fazekasgy@52 97 return
fazekasgy@52 98
fazekasgy@52 99 def getParameter(self,paramid):
fazekasgy@52 100 if paramid == 'threshold' :
fazekasgy@52 101 return self.threshold
fazekasgy@52 102 else:
fazekasgy@52 103 return 0.0
fazekasgy@52 104
fazekasgy@52 105 def process(self,inputbuffers,timestamp):
fazekasgy@52 106
fazekasgy@52 107 # this is a 1 channel frequency domain plugin, therefore
fazekasgy@52 108 # inputbuffers contain (block size / 2) + 1 complex numbers
fazekasgy@52 109 # corresponding to the FFT output from DC to Nyquist inclusive
fazekasgy@52 110
fazekasgy@52 111 cplxArray = inputbuffers[0][:-1]
fazekasgy@52 112
fazekasgy@52 113 prev = self.previousSample
fazekasgy@52 114 numLin = 0.0
fazekasgy@52 115 denom = 0.0
fazekasgy@52 116 centroid = 0.0
fazekasgy@52 117
fazekasgy@52 118 output = FeatureSet()
fazekasgy@52 119
fazekasgy@52 120 pw = 0
fazekasgy@52 121 for i in xrange(1,len(cplxArray)) :
fazekasgy@52 122 pw = pw + abs(cplxArray[i])
fazekasgy@52 123
fazekasgy@52 124 if pw > self.threshold :
fazekasgy@52 125 for i in range(1,(len(cplxArray))) :
fazekasgy@52 126
fazekasgy@52 127 re = cplxArray[i].real
fazekasgy@52 128 im = cplxArray[i].imag
fazekasgy@52 129 freq = i * self.m_inputSampleRate / self.m_blockSize
fazekasgy@52 130 power = sqrt (re*re + im*im) / (self.m_blockSize/2)
fazekasgy@52 131 denom = denom + power
fazekasgy@52 132 numLin = numLin + freq * power
fazekasgy@52 133
fazekasgy@52 134 if denom != 0 :
fazekasgy@52 135 centroid = numLin / denom
fazekasgy@52 136
fazekasgy@52 137 else :
fazekasgy@52 138 centroid = 0.0
fazekasgy@52 139
fazekasgy@52 140 output[0] = Feature()
fazekasgy@52 141 output[0].values = centroid
fazekasgy@52 142 output[0].label = str(centroid)
fazekasgy@52 143
fazekasgy@52 144 return output