comparison spectrum-compare-plugin/TuningDifference.cpp @ 12:23572f9d25d9

Rename & duplicate plugin
author Chris Cannam
date Wed, 04 Feb 2015 10:15:57 +0000
parents spectrum-compare/TuningDifference.cpp@1924df3245f4
children 812e4d021443
comparison
equal deleted inserted replaced
8:08af0d25b61c 12:23572f9d25d9
1
2 #include "TuningDifference.h"
3
4 #include <iostream>
5
6 #include <cmath>
7 #include <cstdio>
8
9 using std::cerr;
10 using std::endl;
11
12 static double targetFmin = 60.0;
13 static double targetFmax = 1500.0;
14
15 TuningDifference::TuningDifference(float inputSampleRate) :
16 Plugin(inputSampleRate)
17 {
18 }
19
20 TuningDifference::~TuningDifference()
21 {
22 }
23
24 string
25 TuningDifference::getIdentifier() const
26 {
27 return "tuning-difference";
28 }
29
30 string
31 TuningDifference::getName() const
32 {
33 return "Tuning Difference";
34 }
35
36 string
37 TuningDifference::getDescription() const
38 {
39 // Return something helpful here!
40 return "";
41 }
42
43 string
44 TuningDifference::getMaker() const
45 {
46 // Your name here
47 return "";
48 }
49
50 int
51 TuningDifference::getPluginVersion() const
52 {
53 // Increment this each time you release a version that behaves
54 // differently from the previous one
55 return 1;
56 }
57
58 string
59 TuningDifference::getCopyright() const
60 {
61 // This function is not ideally named. It does not necessarily
62 // need to say who made the plugin -- getMaker does that -- but it
63 // should indicate the terms under which it is distributed. For
64 // example, "Copyright (year). All Rights Reserved", or "GPL"
65 return "";
66 }
67
68 TuningDifference::InputDomain
69 TuningDifference::getInputDomain() const
70 {
71 return FrequencyDomain;
72 }
73
74 size_t
75 TuningDifference::getPreferredBlockSize() const
76 {
77 return 16384;
78 }
79
80 size_t
81 TuningDifference::getPreferredStepSize() const
82 {
83 return 0;
84 }
85
86 size_t
87 TuningDifference::getMinChannelCount() const
88 {
89 return 2;
90 }
91
92 size_t
93 TuningDifference::getMaxChannelCount() const
94 {
95 return 2;
96 }
97
98 TuningDifference::ParameterList
99 TuningDifference::getParameterDescriptors() const
100 {
101 ParameterList list;
102 return list;
103 }
104
105 float
106 TuningDifference::getParameter(string) const
107 {
108 return 0;
109 }
110
111 void
112 TuningDifference::setParameter(string, float)
113 {
114 }
115
116 TuningDifference::ProgramList
117 TuningDifference::getPrograms() const
118 {
119 ProgramList list;
120 return list;
121 }
122
123 string
124 TuningDifference::getCurrentProgram() const
125 {
126 return ""; // no programs
127 }
128
129 void
130 TuningDifference::selectProgram(string)
131 {
132 }
133
134 TuningDifference::OutputList
135 TuningDifference::getOutputDescriptors() const
136 {
137 OutputList list;
138
139 OutputDescriptor d;
140 d.identifier = "cents";
141 d.name = "Tuning Difference";
142 d.description = "Difference in averaged frequency profile between channels 1 and 2, in cents. A positive value means channel 2 is higher.";
143 d.unit = "cents";
144 d.hasFixedBinCount = true;
145 d.binCount = 1;
146 d.hasKnownExtents = false;
147 d.isQuantized = false;
148 d.sampleType = OutputDescriptor::VariableSampleRate;
149 d.hasDuration = false;
150 list.push_back(d);
151
152 d.identifier = "tuningfreq";
153 d.name = "Relative Tuning Frequency";
154 d.description = "Tuning frequency of channel 2, if channel 1 is assumed to contain the same music as it at a tuning frequency of A=440Hz.";
155 d.unit = "hz";
156 d.hasFixedBinCount = true;
157 d.binCount = 1;
158 d.hasKnownExtents = false;
159 d.isQuantized = false;
160 d.sampleType = OutputDescriptor::VariableSampleRate;
161 d.hasDuration = false;
162 list.push_back(d);
163
164 d.identifier = "curve";
165 d.name = "Shift Correlation Curve";
166 d.description = "Correlation between shifted and unshifted sources, for each probed shift in cents.";
167 d.unit = "";
168 d.hasFixedBinCount = true;
169 d.binCount = 1;
170 d.hasKnownExtents = false;
171 d.isQuantized = false;
172 d.sampleType = OutputDescriptor::FixedSampleRate;
173 d.sampleRate = 100;
174 d.hasDuration = false;
175 list.push_back(d);
176
177 int targetBinMin = int(floor(targetFmin * m_blockSize / m_inputSampleRate));
178 int targetBinMax = int(ceil(targetFmax * m_blockSize / m_inputSampleRate));
179 cerr << "target bin range: " << targetBinMin << " -> " << targetBinMax << endl;
180
181 d.identifier = "averages";
182 d.name = "Spectrum averages";
183 d.description = "Average magnitude spectrum for each channel.";
184 d.unit = "";
185 d.hasFixedBinCount = true;
186 d.binCount = (targetBinMax > targetBinMin ? targetBinMax - targetBinMin + 1 : 100);
187 d.hasKnownExtents = false;
188 d.isQuantized = false;
189 d.sampleType = OutputDescriptor::FixedSampleRate;
190 d.sampleRate = 1;
191 d.hasDuration = false;
192 list.push_back(d);
193
194 return list;
195 }
196
197 bool
198 TuningDifference::initialise(size_t channels, size_t stepSize, size_t blockSize)
199 {
200 if (channels < getMinChannelCount() ||
201 channels > getMaxChannelCount()) return false;
202
203 if (blockSize != getPreferredBlockSize() ||
204 stepSize != blockSize/2) return false;
205
206 m_blockSize = blockSize;
207
208 reset();
209
210 return true;
211 }
212
213 void
214 TuningDifference::reset()
215 {
216 m_sum[0].clear();
217 m_sum[1].clear();
218 m_frameCount = 0;
219 }
220
221 TuningDifference::FeatureSet
222 TuningDifference::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
223 {
224 for (int c = 0; c < 2; ++c) {
225 if (m_sum[c].size() == 0) {
226 m_sum[c].resize(m_blockSize/2 + 1, 0.0);
227 }
228 for (int i = 0; i <= m_blockSize/2; ++i) {
229 double energy =
230 inputBuffers[c][i*2 ] * inputBuffers[c][i*2 ] +
231 inputBuffers[c][i*2+1] * inputBuffers[c][i*2+1];
232 double mag = sqrt(energy);
233 m_sum[c][i] += mag;
234 m_sum[c][i/2] += mag;
235 }
236 }
237
238 ++m_frameCount;
239 return FeatureSet();
240 }
241
242 TuningDifference::FeatureSet
243 TuningDifference::getRemainingFeatures()
244 {
245 int n = m_sum[0].size();
246 if (n == 0) return FeatureSet();
247
248 Feature f;
249 FeatureSet fs;
250
251 int maxshift = 2400; // cents
252
253 int bestshift = -1;
254 double bestdist = 0;
255
256 for (int i = 0; i < n; ++i) {
257 m_sum[0][i] /= m_frameCount;
258 m_sum[1][i] /= m_frameCount;
259 }
260
261 for (int c = 0; c < 2; ++c) {
262 double tot = 0.0;
263 for (int i = 0; i < n; ++i) {
264 tot += m_sum[c][i];
265 }
266 if (tot != 0.0) {
267 for (int i = 0; i < n; ++i) {
268 m_sum[c][i] /= tot;
269 }
270 }
271 }
272
273 int targetBinMin = int(floor(targetFmin * m_blockSize / m_inputSampleRate));
274 int targetBinMax = int(ceil(targetFmax * m_blockSize / m_inputSampleRate));
275 cerr << "target bin range: " << targetBinMin << " -> " << targetBinMax << endl;
276
277 f.values.clear();
278 for (int i = targetBinMin; i < targetBinMax; ++i) {
279 f.values.push_back(m_sum[0][i]);
280 }
281 fs[3].push_back(f);
282 f.values.clear();
283 for (int i = targetBinMin; i < targetBinMax; ++i) {
284 f.values.push_back(m_sum[1][i]);
285 }
286 fs[3].push_back(f);
287
288 f.values.clear();
289
290 for (int shift = -maxshift; shift <= maxshift; ++shift) {
291
292 double multiplier = pow(2.0, double(shift) / 1200.0);
293 double dist = 0.0;
294
295 // cerr << "shift = " << shift << ", multiplier = " << multiplier << endl;
296
297 int contributing = 0;
298
299 for (int i = targetBinMin; i < targetBinMax; ++i) {
300
301 double source = i / multiplier;
302 int s0 = int(source), s1 = s0 + 1;
303 double p1 = source - s0;
304 double p0 = 1.0 - p1;
305
306 double value = 0.0;
307 if (s0 >= 0 && s0 < n) {
308 value += p0 * m_sum[1][s0];
309 ++contributing;
310 }
311 if (s1 >= 0 && s1 < n) {
312 value += p1 * m_sum[1][s1];
313 ++contributing;
314 }
315
316 // if (shift == -1) {
317 // cerr << "for multiplier " << multiplier << ", target " << i << ", source " << source << ", value " << p0 << " * " << m_sum[1][s0] << " + " << p1 << " * " << m_sum[1][s1] << " = " << value << ", other " << m_sum[0][i] << endl;
318 // }
319
320 double diff = fabs(m_sum[0][i] - value);
321 dist += diff;
322 }
323
324 dist /= contributing;
325
326 f.values.clear();
327 f.values.push_back(dist);
328 char label[100];
329 sprintf(label, "%f at shift %d freq mult %f", dist, shift, multiplier);
330 f.label = label;
331 fs[2].push_back(f);
332
333 if (bestshift == -1 || dist < bestdist) {
334 bestshift = shift;
335 bestdist = dist;
336 }
337 }
338
339 f.timestamp = Vamp::RealTime::zeroTime;
340 f.hasTimestamp = true;
341 f.label = "";
342
343 f.values.clear();
344 // cerr << "best dist = " << bestdist << " at shift " << bestshift << endl;
345 f.values.push_back(-bestshift);
346 fs[0].push_back(f);
347
348 f.values.clear();
349 f.values.push_back(440.0 / pow(2.0, double(bestshift) / 1200.0));
350 fs[1].push_back(f);
351
352 return fs;
353 }
354