Mercurial > hg > svgui
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 { |