annotate Example VamPy plugins/PySpectralFeatures.py @ 120:a38d318c85a9 tip

MSVC fixes
author Chris Cannam
date Wed, 18 Dec 2019 16:51:20 +0000
parents f5b8646494d2
children
rev   line source
fazekasgy@37 1 '''PySpectralFeatures.py - Example plugin demonstrates
fazekasgy@37 2 how to calculate and return simple low-level spectral
fazekasgy@37 3 descriptors (curves) using Numpy and the buffer interface.
fazekasgy@37 4
fazekasgy@37 5 Outputs:
fazekasgy@37 6 1) Spectral Centroid
cannam@59 7 2) Spectral Crest Factor
fazekasgy@37 8 3) Spectral Band-width
fazekasgy@37 9 4) Spectral Difference (first order)
fazekasgy@37 10
fazekasgy@37 11 Centre for Digital Music, Queen Mary University of London.
fazekasgy@37 12 Copyright (C) 2009 Gyorgy Fazekas, QMUL. (See Vamp sources
fazekasgy@37 13 for licence information.)
fazekasgy@37 14
fazekasgy@37 15 '''
fazekasgy@37 16
fazekasgy@37 17 from numpy import *
fazekasgy@37 18 from vampy import *
fazekasgy@37 19
fazekasgy@37 20 class PySpectralFeatures:
fazekasgy@37 21
fazekasgy@37 22 def __init__(self,inputSampleRate):
fazekasgy@37 23
fazekasgy@37 24 # flags:
Chris@67 25 self.vampy_flags = vf_BUFFER | vf_REALTIME
fazekasgy@37 26
fazekasgy@37 27 self.m_inputSampleRate = inputSampleRate
fazekasgy@37 28 self.m_stepSize = 0
fazekasgy@37 29 self.m_blockSize = 0
fazekasgy@37 30 self.m_channels = 0
fazekasgy@37 31 self.threshold = 0.05
fazekasgy@37 32 return None
fazekasgy@37 33
fazekasgy@37 34 def initialise(self,channels,stepSize,blockSize):
fazekasgy@37 35 self.m_channels = channels
fazekasgy@37 36 self.m_stepSize = stepSize
fazekasgy@37 37 self.m_blockSize = blockSize
fazekasgy@47 38 self.prevMag = zeros((blockSize/2))
fazekasgy@37 39 return True
fazekasgy@37 40
fazekasgy@37 41 def reset(self):
fazekasgy@37 42 # reset any initial conditions
Chris@68 43 self.prevMag = zeros((self.m_blockSize/2))
fazekasgy@37 44 return None
fazekasgy@37 45
fazekasgy@37 46 def getMaker(self):
fazekasgy@37 47 return 'Vampy Example Plugins'
fazekasgy@37 48
fazekasgy@37 49 def getName(self):
fazekasgy@37 50 return 'Vampy Spectral Features'
fazekasgy@37 51
fazekasgy@37 52 def getIdentifier(self):
fazekasgy@37 53 return 'vampy-sf3'
fazekasgy@37 54
fazekasgy@37 55 def getDescription(self):
fazekasgy@37 56 return 'A collection of low-level spectral descriptors.'
Chris@69 57
Chris@69 58 def getCopyright(self):
Chris@69 59 return 'Plugin By George Fazekas. Freely redistributable example plugin (BSD license)'
Chris@69 60
fazekasgy@37 61 def getMaxChannelCount(self):
fazekasgy@37 62 return 1
fazekasgy@37 63
fazekasgy@37 64 def getInputDomain(self):
fazekasgy@37 65 return FrequencyDomain
fazekasgy@37 66
fazekasgy@37 67 def getOutputDescriptors(self):
fazekasgy@37 68
fazekasgy@37 69 #Generic values are the same for all
fazekasgy@37 70 Generic = OutputDescriptor()
fazekasgy@37 71 Generic.hasFixedBinCount=True
fazekasgy@37 72 Generic.binCount=1
fazekasgy@37 73 Generic.hasKnownExtents=False
fazekasgy@37 74 Generic.isQuantized=False
fazekasgy@37 75 Generic.sampleType = OneSamplePerStep
fazekasgy@37 76 Generic.unit = 'Hz'
fazekasgy@37 77
fazekasgy@37 78 #Spectral centroid etc...
fazekasgy@37 79 SC = OutputDescriptor(Generic)
fazekasgy@37 80 SC.identifier = 'vampy-sc'
fazekasgy@37 81 SC.name = 'Spectral Centroid'
fazekasgy@37 82 SC.description ='Spectral Centroid (Brightness)'
fazekasgy@37 83
fazekasgy@37 84 SCF = OutputDescriptor(Generic)
fazekasgy@37 85 SCF.identifier = 'vampy-scf'
fazekasgy@37 86 SCF.name = 'Spectral Crest Factor'
fazekasgy@37 87 SCF.description = 'Spectral Crest (Tonality)'
fazekasgy@37 88 SCF.unit = 'v'
fazekasgy@37 89
fazekasgy@37 90 BW = OutputDescriptor(Generic)
fazekasgy@37 91 BW.identifier = 'vampy-bw'
fazekasgy@37 92 BW.name = 'Band Width'
fazekasgy@37 93 BW.description = 'Spectral Band Width'
fazekasgy@37 94
fazekasgy@37 95 SD = OutputDescriptor(Generic)
fazekasgy@37 96 SD.identifier = 'vampy-sd'
fazekasgy@37 97 SD.name = 'Spectral Difference'
fazekasgy@37 98 SD.description = 'Eucledian distance of successive magnitude spectra.'
fazekasgy@37 99
fazekasgy@37 100 #return a tuple, list or OutputList(SC,SCF,BW)
fazekasgy@37 101 return OutputList(SC,SCF,BW,SD)
fazekasgy@37 102
fazekasgy@37 103 def getParameterDescriptors(self):
fazekasgy@37 104
fazekasgy@37 105 threshold = ParameterDescriptor()
fazekasgy@37 106 threshold.identifier='threshold'
fazekasgy@37 107 threshold.name='Noise threshold'
Chris@68 108 threshold.description='Magnitude below which a process block will be disregarded and zeroes returned'
fazekasgy@37 109 threshold.unit='v'
fazekasgy@37 110 threshold.minValue=0
fazekasgy@37 111 threshold.maxValue=1
fazekasgy@37 112 threshold.defaultValue=0.05
fazekasgy@37 113 threshold.isQuantized=False
fazekasgy@37 114
fazekasgy@37 115 return ParameterList(threshold)
fazekasgy@37 116
fazekasgy@37 117 def setParameter(self,paramid,newval):
fazekasgy@37 118 if paramid == 'threshold' :
fazekasgy@37 119 self.threshold = newval
fazekasgy@37 120 return
fazekasgy@37 121
fazekasgy@37 122 def getParameter(self,paramid):
fazekasgy@37 123 if paramid == 'threshold' :
fazekasgy@37 124 return self.threshold
fazekasgy@37 125 else:
fazekasgy@37 126 return 0.0
fazekasgy@37 127
fazekasgy@37 128
fazekasgy@37 129 # using the numpy memory buffer interface:
fazekasgy@37 130 # flag : vf_BUFFER (or implement processN)
fazekasgy@37 131 # NOTE: Vampy can now pass numpy arrays directly using
fazekasgy@37 132 # the flag vf_ARRAY (see MFCC plugin for example)
fazekasgy@37 133 def process(self,membuffer,timestamp):
fazekasgy@37 134
fazekasgy@37 135 fftsize = self.m_blockSize
fazekasgy@37 136 sampleRate = self.m_inputSampleRate
fazekasgy@37 137
fazekasgy@37 138 #for time domain plugins use the following line:
fazekasgy@37 139 #audioSamples = frombuffer(membuffer[0],float32)
fazekasgy@37 140
fazekasgy@37 141 #for frequency domain plugins use:
fazekasgy@37 142 complexSpectrum = frombuffer(membuffer[0],complex64,-1,8)
fazekasgy@37 143
fazekasgy@37 144 # meaning of the parameters above:
fazekasgy@37 145 # complex64 : data type of the created numpy array
fazekasgy@37 146 # -1 : convert the whole buffer
fazekasgy@37 147 # 8 : skip the DC component (2*32bit / 8bit = 8byte)
fazekasgy@37 148
fazekasgy@37 149 magnitudeSpectrum = abs(complexSpectrum) / (fftsize*0.5)
fazekasgy@37 150 #phaseSpectrum = angle(complexSpectrum)
fazekasgy@37 151
fazekasgy@37 152 freq = array(range(1,len(complexSpectrum)+1)) \
fazekasgy@37 153 * sampleRate / fftsize
fazekasgy@37 154
fazekasgy@37 155 # return features in a FeatureSet()
fazekasgy@37 156 output_featureSet = FeatureSet()
fazekasgy@37 157
fazekasgy@37 158 tpower = sum(magnitudeSpectrum)
fazekasgy@37 159
fazekasgy@37 160 if tpower > self.threshold :
fazekasgy@37 161 centroid = sum(freq * magnitudeSpectrum) / tpower
fazekasgy@37 162 crest = max(magnitudeSpectrum) / tpower
fazekasgy@37 163 bw = sum( abs(freq - centroid) * magnitudeSpectrum ) / tpower
fazekasgy@37 164 normMag = magnitudeSpectrum / tpower
fazekasgy@37 165 sd = sqrt(sum(power((normMag - self.prevMag),2)))
fazekasgy@37 166 self.prevMag = normMag
fazekasgy@37 167 else :
fazekasgy@37 168 centroid = 0.0
fazekasgy@37 169 crest = 0.0
fazekasgy@37 170 bw = 0.0
fazekasgy@37 171 sd = 0.0
fazekasgy@37 172
fazekasgy@37 173 # Any value resulting from the process can be returned.
fazekasgy@37 174 # It is no longer necessary to wrap single values into lists
fazekasgy@37 175 # and convert numpy.floats to python floats,
fazekasgy@37 176 # however a FeatureList() (or python list) can be returned
fazekasgy@37 177 # if more than one feature is calculated per frame.
fazekasgy@37 178 # The feature values can be e.g. int, float, list or array.
fazekasgy@37 179
fazekasgy@37 180 output_featureSet[0] = Feature(centroid)
fazekasgy@37 181 output_featureSet[1] = Feature(crest)
fazekasgy@37 182 output_featureSet[2] = Feature(bw)
fazekasgy@37 183 output_featureSet[3] = Feature(sd)
fazekasgy@37 184
fazekasgy@37 185 return output_featureSet