comparison Tempogram.cpp @ 0:31d2a7e07786

Moved all to folder "tempogram".
author Carl Bussey <c.bussey@se10.qmul.ac.uk>
date Mon, 07 Jul 2014 10:08:14 +0100
parents
children 3fd1a41b089b
comparison
equal deleted inserted replaced
-1:000000000000 0:31d2a7e07786
1
2 // This is a skeleton file for use in creating your own plugin
3 // libraries. Replace MyPlugin and myPlugin throughout with the name
4 // of your first plugin class, and fill in the gaps as appropriate.
5
6
7 #include "Tempogram.h"
8 #include "FIRFilter.h"
9 #include "WindowFunction.h"
10 #include <vamp-sdk/FFT.h>
11 #include <cmath>
12 #include <fstream>
13 #include <assert.h>
14 using Vamp::FFT;
15 using namespace std;
16
17 Tempogram::Tempogram(float inputSampleRate) :
18 Plugin(inputSampleRate),
19 m_blockSize(0),
20 compressionConstant(1000), //make param
21 previousY(NULL),
22 currentY(NULL),
23 tN(1024), //make param
24 thopSize(512), //make param
25 fftInput(NULL),
26 fftOutputReal(NULL),
27 fftOutputImag(NULL),
28 ncLength(0)
29
30 // Also be sure to set your plugin parameters (presumably stored
31 // in member variables) to their default values here -- the host
32 // will not do that for you
33 {
34 }
35
36 Tempogram::~Tempogram()
37 {
38 //delete stuff
39 }
40
41 string
42 Tempogram::getIdentifier() const
43 {
44 return "tempogram";
45 }
46
47 string
48 Tempogram::getName() const
49 {
50 return "Tempogram";
51 }
52
53 string
54 Tempogram::getDescription() const
55 {
56 // Return something helpful here!
57 return "Cyclic Tempogram as described by Peter Grosche and Meinard Muller";
58 }
59
60 string
61 Tempogram::getMaker() const
62 {
63 //Your name here
64 return "Carl Bussey";
65 }
66
67 int
68 Tempogram::getPluginVersion() const
69 {
70 // Increment this each time you release a version that behaves
71 // differently from the previous one
72 return 1;
73 }
74
75 string
76 Tempogram::getCopyright() const
77 {
78 // This function is not ideally named. It does not necessarily
79 // need to say who made the plugin -- getMaker does that -- but it
80 // should indicate the terms under which it is distributed. For
81 // example, "Copyright (year). All Rights Reserved", or "GPL"
82 return "";
83 }
84
85 Tempogram::InputDomain
86 Tempogram::getInputDomain() const
87 {
88 return FrequencyDomain;
89 }
90
91 size_t
92 Tempogram::getPreferredBlockSize() const
93 {
94 return 0; // 0 means "I can handle any block size"
95 }
96
97 size_t
98 Tempogram::getPreferredStepSize() const
99 {
100 //23 ms?
101 return 0; // 0 means "anything sensible"; in practice this
102 // means the same as the block size for TimeDomain
103 // plugins, or half of it for FrequencyDomain plugins
104 }
105
106 size_t
107 Tempogram::getMinChannelCount() const
108 {
109 return 1;
110 }
111
112 size_t
113 Tempogram::getMaxChannelCount() const
114 {
115 return 1;
116 }
117
118 Tempogram::ParameterList
119 Tempogram::getParameterDescriptors() const
120 {
121 ParameterList list;
122
123 // If the plugin has no adjustable parameters, return an empty
124 // list here (and there's no need to provide implementations of
125 // getParameter and setParameter in that case either).
126
127 // Note that it is your responsibility to make sure the parameters
128 // start off having their default values (e.g. in the constructor
129 // above). The host needs to know the default value so it can do
130 // things like provide a "reset to default" function, but it will
131 // not explicitly set your parameters to their defaults for you if
132 // they have not changed in the mean time.
133
134 ParameterDescriptor C;
135 C.identifier = "C";
136 C.name = "C";
137 C.description = "Spectrogram compression constant, C";
138 C.unit = "";
139 C.minValue = 2;
140 C.maxValue = 10000;
141 C.defaultValue = 1000;
142 C.isQuantized = false;
143 list.push_back(C);
144
145 ParameterDescriptor tN;
146 tN.identifier = "tN";
147 tN.name = "Tempogram FFT length";
148 tN.description = "Tempogram FFT length.";
149 tN.unit = "";
150 tN.minValue = 128;
151 tN.maxValue = 4096;
152 tN.defaultValue = 1024;
153 tN.isQuantized = true;
154 tN.quantizeStep = 128;
155 list.push_back(tN);
156
157 return list;
158 }
159
160 float
161 Tempogram::getParameter(string identifier) const
162 {
163 if (identifier == "C") {
164 return compressionConstant; // return the ACTUAL current value of your parameter here!
165 }
166 if (identifier == "tN"){
167 return tN;
168 }
169
170 return 0;
171 }
172
173 void
174 Tempogram::setParameter(string identifier, float value)
175 {
176 if (identifier == "C") {
177 compressionConstant = value;// set the actual value of your parameter
178 }
179 if (identifier == "tN") {
180 tN = value;
181 }
182 }
183
184 Tempogram::ProgramList
185 Tempogram::getPrograms() const
186 {
187 ProgramList list;
188
189 // If you have no programs, return an empty list (or simply don't
190 // implement this function or getCurrentProgram/selectProgram)
191
192 return list;
193 }
194
195 string
196 Tempogram::getCurrentProgram() const
197 {
198 return ""; // no programs
199 }
200
201 void
202 Tempogram::selectProgram(string name)
203 {
204 }
205
206 Tempogram::OutputList
207 Tempogram::getOutputDescriptors() const
208 {
209 OutputList list;
210
211 // See OutputDescriptor documentation for the possibilities here.
212 // Every plugin must have at least one output.
213
214 OutputDescriptor d;
215 d.identifier = "output";
216 d.name = "Cyclic Tempogram";
217 d.description = "Cyclic Tempogram";
218 d.unit = "";
219 d.hasFixedBinCount = false;
220 //d.binCount = 1;
221 d.hasKnownExtents = false;
222 d.isQuantized = false;
223 d.sampleType = OutputDescriptor::VariableSampleRate;
224 d.sampleRate = 0.0;
225 d.hasDuration = false;
226 list.push_back(d);
227
228 return list;
229 }
230
231 bool
232 Tempogram::initialise(size_t channels, size_t stepSize, size_t blockSize)
233 {
234 if (channels < getMinChannelCount() ||
235 channels > getMaxChannelCount()) return false;
236
237 // Real initialisation work goes here!
238 m_blockSize = blockSize;
239 currentY = new float[m_blockSize];
240 previousY = new float[m_blockSize];
241
242 return true;
243 }
244
245 void
246 Tempogram::reset()
247 {
248 // Clear buffers, reset stored values, etc
249 }
250
251 Tempogram::FeatureSet
252 Tempogram::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
253 {
254 size_t n = m_blockSize/2 + 1;
255
256 FeatureSet featureSet;
257 Feature feature;
258 feature.hasTimestamp = false;
259
260 const float *in = inputBuffers[0];
261
262 //Calculate log magnitude
263 float sum = 0;
264 for (int i = 0; i < n; i++){
265 float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]);
266 currentY[i] = log(1+compressionConstant*magnitude); //should be 1+C*magnitude
267 if(currentY[i] >= previousY[i]){
268 sum += (currentY[i] - previousY[i]);
269 }
270 }
271
272 noveltyCurve.push_back(sum);
273
274 float *tmpY = currentY;
275 currentY = previousY;
276 previousY = tmpY;
277
278 ncTimestamps.push_back(timestamp);
279
280 return FeatureSet();
281 }
282
283 void
284 Tempogram::initialiseForGRF(){
285 hannN = 129;
286 hannWindow = new float[hannN];
287 hannWindowtN = new float[tN];
288 fftInput = new double[tN];
289 fftOutputReal = new double[tN];
290 fftOutputImag = new double[tN];
291 ncLength = noveltyCurve.size();
292
293 WindowFunction::hanning(hannWindow, hannN, true);
294 }
295
296 void
297 Tempogram::cleanupForGRF(){
298 delete []hannWindow;
299 hannWindow = NULL;
300 delete []hannWindowtN;
301 hannWindowtN = NULL;
302 delete []fftInput;
303 fftInput = NULL;
304 delete []fftOutputReal;
305 fftOutputReal = NULL;
306 delete []fftOutputImag;
307 fftOutputImag = NULL;
308 }
309
310 Tempogram::FeatureSet
311 Tempogram::getRemainingFeatures()
312 {
313 //Make sure this is called at the beginning of the function
314 initialiseForGRF();
315
316 vector<float> noveltyCurveLocalAverage(ncLength);
317
318 FIRFilter *filter = new FIRFilter(ncLength, hannN);
319 filter->process(&noveltyCurve[0], hannWindow, &noveltyCurveLocalAverage[0]);
320 delete filter;
321
322 for(int i = 0; i < ncLength; i++){
323 noveltyCurve[i] -= noveltyCurveLocalAverage[i];
324 noveltyCurve[i] = noveltyCurve[i] >= 0 ? noveltyCurve[i] : 0;
325 }
326
327 int i=0;
328 WindowFunction::hanning(hannWindowtN, tN);
329
330 int index;
331 int start = floor(tN/2 + 0.5);
332 int timestampInc = floor((((float)ncTimestamps[1].nsec - ncTimestamps[0].nsec)/1e9)*(thopSize) + 0.5);
333 //cout << timestampInc << endl;
334
335 FeatureSet featureSet;
336
337 while(i < ncLength){
338 Feature feature;
339 Vamp::RealTime timestamp;
340
341 for (int n = start; n < tN; n++){
342 index = i + n - tN/2;
343 assert (index >= 0);
344
345 if(index < ncLength){
346 fftInput[n] = noveltyCurve[i + n] * hannWindowtN[n];
347 }
348 else if(index >= ncLength){
349 fftInput[n] = 0.0; //pad the end with zeros
350 }
351 //cout << fftInput[n] << endl;
352 }
353 if (i+tN/2 > ncLength){
354 timestamp = Vamp::RealTime::fromSeconds(ncTimestamps[i].sec + timestampInc);
355 }
356 else{
357 timestamp = ncTimestamps[i + tN/2];
358 }
359
360 FFT::forward(tN, fftInput, NULL, fftOutputReal, fftOutputImag);
361
362 //TODO: sample at logarithmic spacing
363 for(int k = 0; k < tN; k++){
364 double fftOutputPower = (fftOutputReal[k]*fftOutputReal[k] + fftOutputImag[k]*fftOutputImag[k]); //Magnitude or power?
365 assert (!isinf(fftOutputPower));
366
367 feature.values.push_back(fftOutputPower);
368 }
369
370 i += thopSize;
371 start = 0;
372
373 feature.timestamp = timestamp;
374 feature.hasTimestamp = true;
375 featureSet[0].push_back(feature);
376 }
377
378 //Make sure this is called at the end of the function
379 cleanupForGRF();
380
381 return featureSet;
382 }