Mercurial > hg > tuning-difference
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 |