annotate Example VamPy plugins/PySpectralCentroid.py @ 92:a6718f9fe942

If a module appears to redefine one of our own types, refuse to load it. Also clear out the class dict for all refused modules now, so that we don't get stale names on the next scan due to not having cleared the module on unload
author Chris Cannam
date Mon, 14 Jan 2019 16:19:44 +0000
parents 6c755f3e1173
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