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
|
fazekasgy@37
|
7 2) Spectral Creast 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:
|
fazekasgy@37
|
25 self.vampy_flags = vf_DEBUG | 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
|
fazekasgy@47
|
43 self.prevMag = zeros((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.'
|
fazekasgy@37
|
57
|
fazekasgy@37
|
58 def getMaxChannelCount(self):
|
fazekasgy@37
|
59 return 1
|
fazekasgy@37
|
60
|
fazekasgy@37
|
61 def getInputDomain(self):
|
fazekasgy@37
|
62 return FrequencyDomain
|
fazekasgy@37
|
63
|
fazekasgy@37
|
64 def getOutputDescriptors(self):
|
fazekasgy@37
|
65
|
fazekasgy@37
|
66 #Generic values are the same for all
|
fazekasgy@37
|
67 Generic = OutputDescriptor()
|
fazekasgy@37
|
68 Generic.hasFixedBinCount=True
|
fazekasgy@37
|
69 Generic.binCount=1
|
fazekasgy@37
|
70 Generic.hasKnownExtents=False
|
fazekasgy@37
|
71 Generic.isQuantized=False
|
fazekasgy@37
|
72 Generic.sampleType = OneSamplePerStep
|
fazekasgy@37
|
73 Generic.unit = 'Hz'
|
fazekasgy@37
|
74
|
fazekasgy@37
|
75 #Spectral centroid etc...
|
fazekasgy@37
|
76 SC = OutputDescriptor(Generic)
|
fazekasgy@37
|
77 SC.identifier = 'vampy-sc'
|
fazekasgy@37
|
78 SC.name = 'Spectral Centroid'
|
fazekasgy@37
|
79 SC.description ='Spectral Centroid (Brightness)'
|
fazekasgy@37
|
80
|
fazekasgy@37
|
81 SCF = OutputDescriptor(Generic)
|
fazekasgy@37
|
82 SCF.identifier = 'vampy-scf'
|
fazekasgy@37
|
83 SCF.name = 'Spectral Crest Factor'
|
fazekasgy@37
|
84 SCF.description = 'Spectral Crest (Tonality)'
|
fazekasgy@37
|
85 SCF.unit = 'v'
|
fazekasgy@37
|
86
|
fazekasgy@37
|
87 BW = OutputDescriptor(Generic)
|
fazekasgy@37
|
88 BW.identifier = 'vampy-bw'
|
fazekasgy@37
|
89 BW.name = 'Band Width'
|
fazekasgy@37
|
90 BW.description = 'Spectral Band Width'
|
fazekasgy@37
|
91
|
fazekasgy@37
|
92 SD = OutputDescriptor(Generic)
|
fazekasgy@37
|
93 SD.identifier = 'vampy-sd'
|
fazekasgy@37
|
94 SD.name = 'Spectral Difference'
|
fazekasgy@37
|
95 SD.description = 'Eucledian distance of successive magnitude spectra.'
|
fazekasgy@37
|
96
|
fazekasgy@37
|
97 #return a tuple, list or OutputList(SC,SCF,BW)
|
fazekasgy@37
|
98 return OutputList(SC,SCF,BW,SD)
|
fazekasgy@37
|
99
|
fazekasgy@37
|
100 def getParameterDescriptors(self):
|
fazekasgy@37
|
101
|
fazekasgy@37
|
102 threshold = ParameterDescriptor()
|
fazekasgy@37
|
103 threshold.identifier='threshold'
|
fazekasgy@37
|
104 threshold.name='Noise threshold'
|
fazekasgy@37
|
105 threshold.description='Noise threshold'
|
fazekasgy@37
|
106 threshold.unit='v'
|
fazekasgy@37
|
107 threshold.minValue=0
|
fazekasgy@37
|
108 threshold.maxValue=1
|
fazekasgy@37
|
109 threshold.defaultValue=0.05
|
fazekasgy@37
|
110 threshold.isQuantized=False
|
fazekasgy@37
|
111
|
fazekasgy@37
|
112 return ParameterList(threshold)
|
fazekasgy@37
|
113
|
fazekasgy@37
|
114 def setParameter(self,paramid,newval):
|
fazekasgy@37
|
115 if paramid == 'threshold' :
|
fazekasgy@37
|
116 self.threshold = newval
|
fazekasgy@37
|
117 return
|
fazekasgy@37
|
118
|
fazekasgy@37
|
119 def getParameter(self,paramid):
|
fazekasgy@37
|
120 if paramid == 'threshold' :
|
fazekasgy@37
|
121 return self.threshold
|
fazekasgy@37
|
122 else:
|
fazekasgy@37
|
123 return 0.0
|
fazekasgy@37
|
124
|
fazekasgy@37
|
125
|
fazekasgy@37
|
126 # using the numpy memory buffer interface:
|
fazekasgy@37
|
127 # flag : vf_BUFFER (or implement processN)
|
fazekasgy@37
|
128 # NOTE: Vampy can now pass numpy arrays directly using
|
fazekasgy@37
|
129 # the flag vf_ARRAY (see MFCC plugin for example)
|
fazekasgy@37
|
130 def process(self,membuffer,timestamp):
|
fazekasgy@37
|
131
|
fazekasgy@37
|
132 fftsize = self.m_blockSize
|
fazekasgy@37
|
133 sampleRate = self.m_inputSampleRate
|
fazekasgy@37
|
134
|
fazekasgy@37
|
135 #for time domain plugins use the following line:
|
fazekasgy@37
|
136 #audioSamples = frombuffer(membuffer[0],float32)
|
fazekasgy@37
|
137
|
fazekasgy@37
|
138 #for frequency domain plugins use:
|
fazekasgy@37
|
139 complexSpectrum = frombuffer(membuffer[0],complex64,-1,8)
|
fazekasgy@37
|
140
|
fazekasgy@37
|
141 # meaning of the parameters above:
|
fazekasgy@37
|
142 # complex64 : data type of the created numpy array
|
fazekasgy@37
|
143 # -1 : convert the whole buffer
|
fazekasgy@37
|
144 # 8 : skip the DC component (2*32bit / 8bit = 8byte)
|
fazekasgy@37
|
145
|
fazekasgy@37
|
146 magnitudeSpectrum = abs(complexSpectrum) / (fftsize*0.5)
|
fazekasgy@37
|
147 #phaseSpectrum = angle(complexSpectrum)
|
fazekasgy@37
|
148
|
fazekasgy@37
|
149 freq = array(range(1,len(complexSpectrum)+1)) \
|
fazekasgy@37
|
150 * sampleRate / fftsize
|
fazekasgy@37
|
151
|
fazekasgy@37
|
152 # return features in a FeatureSet()
|
fazekasgy@37
|
153 output_featureSet = FeatureSet()
|
fazekasgy@37
|
154
|
fazekasgy@37
|
155 tpower = sum(magnitudeSpectrum)
|
fazekasgy@37
|
156
|
fazekasgy@37
|
157 if tpower > self.threshold :
|
fazekasgy@37
|
158 centroid = sum(freq * magnitudeSpectrum) / tpower
|
fazekasgy@37
|
159 crest = max(magnitudeSpectrum) / tpower
|
fazekasgy@37
|
160 bw = sum( abs(freq - centroid) * magnitudeSpectrum ) / tpower
|
fazekasgy@37
|
161 normMag = magnitudeSpectrum / tpower
|
fazekasgy@37
|
162 sd = sqrt(sum(power((normMag - self.prevMag),2)))
|
fazekasgy@37
|
163 self.prevMag = normMag
|
fazekasgy@37
|
164 else :
|
fazekasgy@37
|
165 centroid = 0.0
|
fazekasgy@37
|
166 crest = 0.0
|
fazekasgy@37
|
167 bw = 0.0
|
fazekasgy@37
|
168 sd = 0.0
|
fazekasgy@37
|
169
|
fazekasgy@37
|
170 # Any value resulting from the process can be returned.
|
fazekasgy@37
|
171 # It is no longer necessary to wrap single values into lists
|
fazekasgy@37
|
172 # and convert numpy.floats to python floats,
|
fazekasgy@37
|
173 # however a FeatureList() (or python list) can be returned
|
fazekasgy@37
|
174 # if more than one feature is calculated per frame.
|
fazekasgy@37
|
175 # The feature values can be e.g. int, float, list or array.
|
fazekasgy@37
|
176
|
fazekasgy@37
|
177 output_featureSet[0] = Feature(centroid)
|
fazekasgy@37
|
178 output_featureSet[1] = Feature(crest)
|
fazekasgy@37
|
179 output_featureSet[2] = Feature(bw)
|
fazekasgy@37
|
180 output_featureSet[3] = Feature(sd)
|
fazekasgy@37
|
181
|
fazekasgy@37
|
182 return output_featureSet
|