comparison layer/SliceLayer.cpp @ 1394:4a36f6130056 spectrogramparam

Various tweaks & fixes to log-scale handling in spectrum. We can't easily preserve the nice behaviour where peaks stay in place as fft size changes, without potentially losing a bit of low-frequency information
author Chris Cannam
date Wed, 14 Nov 2018 14:17:06 +0000
parents 1eb560b363e7
children ba1f0234efa7
comparison
equal deleted inserted replaced
1393:a0bfe366f9cb 1394:4a36f6130056
202 SliceLayer::getXForScalePoint(const LayerGeometryProvider *v, 202 SliceLayer::getXForScalePoint(const LayerGeometryProvider *v,
203 double p, double pmin, double pmax) const 203 double p, double pmin, double pmax) const
204 { 204 {
205 double x = 0; 205 double x = 0;
206 206
207 p -= pmin;
208 if (p < 0) p = 0;
209
210 double extent = pmax - pmin;
211 if (extent < 0) extent = 0;
212
213 int pw = v->getPaintWidth(); 207 int pw = v->getPaintWidth();
214 int origin = m_xorigins[v->getId()]; 208 int origin = m_xorigins[v->getId()];
215 int w = pw - origin; 209 int w = pw - origin;
216 if (w < 1) w = 1; 210 if (w < 1) w = 1;
217 211
218 switch (m_binScale) { 212 if (p < pmin) p = pmin;
219 213 if (p > pmax) p = pmax;
220 case LinearBins: 214
221 x = (w * p) / extent; 215 if (m_binScale == LinearBins) {
222 break; 216 x = (w * (p - pmin)) / (pmax - pmin);
223 217 } else {
224 case LogBins: 218
219 if (m_binScale == InvertedLogBins) {
220 // stoopid
221 p = pmax - p;
222 }
223
225 // The 0.8 here is an awkward compromise. Our x-coord is 224 // The 0.8 here is an awkward compromise. Our x-coord is
226 // proportional to log of bin number, with the x-coord "of a 225 // proportional to log of bin number, with the x-coord "of a
227 // bin" being that of the left edge of the bin range. We can't 226 // bin" being that of the left edge of the bin range. We can't
228 // start counting bins from 0, as that would give us x = -Inf 227 // start counting bins from 0, as that would give us x = -Inf
229 // and hide the first bin entirely. But if we start from 1, we 228 // and hide the first bin entirely. But if we start from 1, we
232 // for that bin is in the middle of it. Yet in some modes 231 // for that bin is in the middle of it. Yet in some modes
233 // we'll still want it. A compromise is to count our first bin 232 // we'll still want it. A compromise is to count our first bin
234 // as "a bit less than 1", so that most of it is visible but a 233 // as "a bit less than 1", so that most of it is visible but a
235 // bit is tactfully cropped at the left edge so it doesn't 234 // bit is tactfully cropped at the left edge so it doesn't
236 // take up so much space. 235 // take up so much space.
237 x = (w * log10(p + 0.8)) / log10(extent + 0.8); 236 const double origin = 0.8;
238 break; 237
239 238 // sometimes we are called with a pmin/pmax range that begins
240 case InvertedLogBins: 239 // before 0: in that situation, we shift everything along by
241 x = w - (w * log10(extent - p - 1)) / log10(extent); 240 // the difference between 0 and pmin before doing any other
242 break; 241 // calculations
242 double reqdshift = 0.0;
243 if (pmin < 0) reqdshift = -pmin;
244
245 double pminlog = log10(pmin + reqdshift + origin);
246 double pmaxlog = log10(pmax + reqdshift + origin);
247 double plog = log10(p + reqdshift + origin);
248 x = (w * (plog - pminlog)) / (pmaxlog - pminlog);
249
250 /*
251 cerr << "getXForScalePoint(" << p << "): pmin = " << pmin
252 << ", pmax = " << pmax << ", w = " << w
253 << ", reqdshift = " << reqdshift
254 << ", pminlog = " << pminlog << ", pmaxlog = " << pmaxlog
255 << ", plog = " << plog
256 << " -> x = " << x << endl;
257 */
258
259 if (m_binScale == InvertedLogBins) {
260 // still stoopid
261 x = w - x;
262 }
243 } 263 }
244 264
245 return x + origin; 265 return x + origin;
246 } 266 }
247 267
255 SliceLayer::getScalePointForX(const LayerGeometryProvider *v, 275 SliceLayer::getScalePointForX(const LayerGeometryProvider *v,
256 double x, double pmin, double pmax) const 276 double x, double pmin, double pmax) const
257 { 277 {
258 double p = 0; 278 double p = 0;
259 279
260 double extent = pmax - pmin;
261 if (extent < 0) extent = 0;
262
263 int pw = v->getPaintWidth(); 280 int pw = v->getPaintWidth();
264 int origin = m_xorigins[v->getId()]; 281 int origin = m_xorigins[v->getId()];
265 282
266 int w = pw - origin; 283 int w = pw - origin;
267 if (w < 1) w = 1; 284 if (w < 1) w = 1;
268 285
269 x = x - origin; 286 x = x - origin;
270 if (x < 0) x = 0; 287 if (x < 0) x = 0;
271 288
272 double eps = 1e-10; 289 double eps = 1e-10;
273 290
274 switch (m_binScale) { 291 if (m_binScale == LinearBins) {
275 292 p = pmin + eps + (x * (pmax - pmin)) / w;
276 case LinearBins: 293 } else {
277 p = (x * extent) / w + eps; 294
278 break; 295 if (m_binScale == InvertedLogBins) {
279 296 x = w - x;
280 case LogBins: 297 }
281 // See comment in getXForScalePoint 298
282 p = pow(10.0, (x * log10(extent + 0.8)) / w) - 0.8 + eps; 299 // See comments in getXForScalePoint
283 break; 300
284 301 const double origin = 0.8;
285 case InvertedLogBins: 302 double reqdshift = 0.0;
286 p = extent + 1 - pow(10.0, (log10(extent) * (w - x)) / double(w)) + eps; 303 if (pmin < 0) reqdshift = -pmin;
287 break; 304
288 } 305 double pminlog = log10(pmin + reqdshift + origin);
289 306 double pmaxlog = log10(pmax + reqdshift + origin);
290 return p + pmin; 307
308 double plog = pminlog + eps + (x * (pmaxlog - pminlog)) / w;
309 p = pow(10.0, plog) - reqdshift - origin;
310
311 if (m_binScale == InvertedLogBins) {
312 p = pmax - p;
313 }
314 }
315
316 return p;
291 } 317 }
292 318
293 double 319 double
294 SliceLayer::getYForValue(const LayerGeometryProvider *v, double value, double &norm) const 320 SliceLayer::getYForValue(const LayerGeometryProvider *v, double value, double &norm) const
295 { 321 {