annotate Example VamPy plugins/PySpectralCentroid.py @ 70:6c755f3e1173

More fixes
author Chris Cannam
date Mon, 17 Nov 2014 14:07:00 +0000
parents f5b8646494d2
children
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
Chris@69 7 legacy interface: the FFT output 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_stepSize = 0
fazekasgy@52 39 self.m_blockSize = 0
fazekasgy@52 40 self.m_channels = 0
fazekasgy@52 41 self.previousSample = 0.0
fazekasgy@52 42 self.m_inputSampleRate = inputSampleRate
Chris@68 43 self.threshold = 0.05
fazekasgy@52 44
fazekasgy@52 45 def initialise(self,channels,stepSize,blockSize):
fazekasgy@52 46 self.m_channels = channels
fazekasgy@52 47 self.m_stepSize = stepSize
fazekasgy@52 48 self.m_blockSize = blockSize
fazekasgy@52 49 return True
fazekasgy@52 50
fazekasgy@52 51 def getMaker(self):
fazekasgy@52 52 return 'Vampy Example Plugins'
fazekasgy@52 53
fazekasgy@52 54 def getName(self):
fazekasgy@52 55 return 'Spectral Centroid (using legacy process interface)'
fazekasgy@52 56
fazekasgy@52 57 def getIdentifier(self):
fazekasgy@52 58 return 'vampy-sc3'
Chris@69 59
Chris@69 60 def getDescription(self):
Chris@69 61 return 'Calculate the linear frequency centroid of the short-time Fourier spectrum'
Chris@69 62
Chris@69 63 def getCopyright(self):
Chris@69 64 return 'Plugin By George Fazekas. Freely redistributable example plugin (BSD license)'
Chris@69 65
fazekasgy@52 66 def getMaxChannelCount(self):
fazekasgy@52 67 return 1
fazekasgy@52 68
fazekasgy@52 69 def getInputDomain(self):
fazekasgy@52 70 return FrequencyDomain
fazekasgy@52 71
fazekasgy@52 72 def getOutputDescriptors(self):
fazekasgy@52 73
fazekasgy@52 74 cod = OutputDescriptor()
fazekasgy@52 75 cod.identifier='vampy-sc3'
fazekasgy@52 76 cod.name='Spectral Centroid'
fazekasgy@52 77 cod.description='Spectral Centroid (Brightness)'
fazekasgy@52 78 cod.unit=''
fazekasgy@52 79 cod.hasFixedBinCount=True
fazekasgy@52 80 cod.binCount=1
fazekasgy@52 81 cod.hasKnownExtents=False
fazekasgy@52 82 cod.isQuantized=True
fazekasgy@52 83 cod.quantizeStep=1.0
fazekasgy@52 84 cod.sampleType=OneSamplePerStep
fazekasgy@52 85 return cod
fazekasgy@52 86
fazekasgy@52 87 def getParameterDescriptors(self):
fazekasgy@52 88 thd = ParameterDescriptor()
fazekasgy@52 89 thd.identifier='threshold'
fazekasgy@52 90 thd.name='Noise threshold'
Chris@68 91 thd.description='Magnitude below which a process block will be disregarded and zero returned'
fazekasgy@52 92 thd.unit='v'
fazekasgy@52 93 thd.minValue=0.0
fazekasgy@52 94 thd.maxValue=0.5
fazekasgy@52 95 thd.defaultValue=0.05
fazekasgy@52 96 thd.isQuantized=False
fazekasgy@52 97 return thd
fazekasgy@52 98
fazekasgy@52 99 def setParameter(self,paramid,newval):
fazekasgy@52 100 if paramid == 'threshold' :
fazekasgy@52 101 self.threshold = newval
fazekasgy@52 102 return
fazekasgy@52 103
fazekasgy@52 104 def getParameter(self,paramid):
fazekasgy@52 105 if paramid == 'threshold' :
fazekasgy@52 106 return self.threshold
fazekasgy@52 107 else:
fazekasgy@52 108 return 0.0
fazekasgy@52 109
fazekasgy@52 110 def process(self,inputbuffers,timestamp):
fazekasgy@52 111
fazekasgy@52 112 # this is a 1 channel frequency domain plugin, therefore
fazekasgy@52 113 # inputbuffers contain (block size / 2) + 1 complex numbers
fazekasgy@52 114 # corresponding to the FFT output from DC to Nyquist inclusive
fazekasgy@52 115
fazekasgy@52 116 cplxArray = inputbuffers[0][:-1]
fazekasgy@52 117
fazekasgy@52 118 prev = self.previousSample
fazekasgy@52 119 numLin = 0.0
fazekasgy@52 120 denom = 0.0
fazekasgy@52 121 centroid = 0.0
fazekasgy@52 122
fazekasgy@52 123 output = FeatureSet()
fazekasgy@52 124
fazekasgy@52 125 pw = 0
fazekasgy@52 126 for i in xrange(1,len(cplxArray)) :
fazekasgy@52 127 pw = pw + abs(cplxArray[i])
fazekasgy@52 128
fazekasgy@52 129 if pw > self.threshold :
fazekasgy@52 130 for i in range(1,(len(cplxArray))) :
fazekasgy@52 131
fazekasgy@52 132 re = cplxArray[i].real
fazekasgy@52 133 im = cplxArray[i].imag
fazekasgy@52 134 freq = i * self.m_inputSampleRate / self.m_blockSize
fazekasgy@52 135 power = sqrt (re*re + im*im) / (self.m_blockSize/2)
fazekasgy@52 136 denom = denom + power
fazekasgy@52 137 numLin = numLin + freq * power
fazekasgy@52 138
fazekasgy@52 139 if denom != 0 :
fazekasgy@52 140 centroid = numLin / denom
fazekasgy@52 141
fazekasgy@52 142 else :
fazekasgy@52 143 centroid = 0.0
fazekasgy@52 144
fazekasgy@52 145 output[0] = Feature()
fazekasgy@52 146 output[0].values = centroid
fazekasgy@52 147 output[0].label = str(centroid)
fazekasgy@52 148
fazekasgy@52 149 return output