1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Vamp
5 
6     An API for audio analysis and feature extraction plugins.
7 
8     Centre for Digital Music, Queen Mary, University of London.
9     Copyright 2006 Chris Cannam.
10 
11     Permission is hereby granted, free of charge, to any person
12     obtaining a copy of this software and associated documentation
13     files (the "Software"), to deal in the Software without
14     restriction, including without limitation the rights to use, copy,
15     modify, merge, publish, distribute, sublicense, and/or sell copies
16     of the Software, and to permit persons to whom the Software is
17     furnished to do so, subject to the following conditions:
18 
19     The above copyright notice and this permission notice shall be
20     included in all copies or substantial portions of the Software.
21 
22     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
26     ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27     CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 
30     Except as contained in this notice, the names of the Centre for
31     Digital Music; Queen Mary, University of London; and Chris Cannam
32     shall not be used in advertising or otherwise to promote the sale,
33     use or other dealings in this Software without prior written
34     authorization.
35 */
36 
37 #include "SpectralCentroid.h"
38 
39 using std::string;
40 using std::vector;
41 using std::cerr;
42 using std::endl;
43 
44 #include <math.h>
45 
46 #ifdef __SUNPRO_CC
47 #include <ieeefp.h>
48 #define isinf(x) (!finite(x))
49 #endif
50 
51 #ifdef WIN32
52 #define isnan(x) false
53 #define isinf(x) false
54 #endif
55 
SpectralCentroid(float inputSampleRate)56 SpectralCentroid::SpectralCentroid(float inputSampleRate) :
57     Plugin(inputSampleRate),
58     m_stepSize(0),
59     m_blockSize(0)
60 {
61 }
62 
~SpectralCentroid()63 SpectralCentroid::~SpectralCentroid()
64 {
65 }
66 
67 string
getIdentifier() const68 SpectralCentroid::getIdentifier() const
69 {
70     return "spectralcentroid";
71 }
72 
73 string
getName() const74 SpectralCentroid::getName() const
75 {
76     return "Spectral Centroid";
77 }
78 
79 string
getDescription() const80 SpectralCentroid::getDescription() const
81 {
82     return "Calculate the centroid frequency of the spectrum of the input signal";
83 }
84 
85 string
getMaker() const86 SpectralCentroid::getMaker() const
87 {
88     return "Vamp SDK Example Plugins";
89 }
90 
91 int
getPluginVersion() const92 SpectralCentroid::getPluginVersion() const
93 {
94     return 2;
95 }
96 
97 string
getCopyright() const98 SpectralCentroid::getCopyright() const
99 {
100     return "Freely redistributable (BSD license)";
101 }
102 
103 bool
initialise(size_t channels,size_t stepSize,size_t blockSize)104 SpectralCentroid::initialise(size_t channels, size_t stepSize, size_t blockSize)
105 {
106     if (channels < getMinChannelCount() ||
107 	channels > getMaxChannelCount()) return false;
108 
109     m_stepSize = stepSize;
110     m_blockSize = blockSize;
111 
112     return true;
113 }
114 
115 void
reset()116 SpectralCentroid::reset()
117 {
118 }
119 
120 SpectralCentroid::OutputList
getOutputDescriptors() const121 SpectralCentroid::getOutputDescriptors() const
122 {
123     OutputList list;
124 
125     OutputDescriptor d;
126     d.identifier = "logcentroid";
127     d.name = "Log Frequency Centroid";
128     d.description = "Centroid of the log weighted frequency spectrum";
129     d.unit = "Hz";
130     d.hasFixedBinCount = true;
131     d.binCount = 1;
132     d.hasKnownExtents = false;
133     d.isQuantized = false;
134     d.sampleType = OutputDescriptor::OneSamplePerStep;
135     list.push_back(d);
136 
137     d.identifier = "linearcentroid";
138     d.name = "Linear Frequency Centroid";
139     d.description = "Centroid of the linear frequency spectrum";
140     list.push_back(d);
141 
142     return list;
143 }
144 
145 SpectralCentroid::FeatureSet
process(const float * const * inputBuffers,Vamp::RealTime timestamp)146 SpectralCentroid::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
147 {
148     if (m_stepSize == 0) {
149 	cerr << "ERROR: SpectralCentroid::process: "
150 	     << "SpectralCentroid has not been initialised"
151 	     << endl;
152 	return FeatureSet();
153     }
154 
155     double numLin = 0.0, numLog = 0.0, denom = 0.0;
156 
157     for (size_t i = 1; i <= m_blockSize/2; ++i) {
158 	double freq = (double(i) * m_inputSampleRate) / m_blockSize;
159 	double real = inputBuffers[0][i*2];
160 	double imag = inputBuffers[0][i*2 + 1];
161 	double scalemag = sqrt(real * real + imag * imag) / (m_blockSize/2);
162 	numLin += freq * scalemag;
163         numLog += log10f(freq) * scalemag;
164 	denom += scalemag;
165     }
166 
167     FeatureSet returnFeatures;
168 
169     if (denom != 0.0) {
170 	float centroidLin = float(numLin / denom);
171 	float centroidLog = powf(10, float(numLog / denom));
172 
173 	Feature feature;
174 	feature.hasTimestamp = false;
175 
176         if (!isnan(centroidLog) && !isinf(centroidLog)) {
177             feature.values.push_back(centroidLog);
178         }
179 	returnFeatures[0].push_back(feature);
180 
181         feature.values.clear();
182         if (!isnan(centroidLin) && !isinf(centroidLin)) {
183             feature.values.push_back(centroidLin);
184         }
185 	returnFeatures[1].push_back(feature);
186     }
187 
188     return returnFeatures;
189 }
190 
191 SpectralCentroid::FeatureSet
getRemainingFeatures()192 SpectralCentroid::getRemainingFeatures()
193 {
194     return FeatureSet();
195 }
196 
197