annotate base/LogRange.cpp @ 1188:d9698ee93659 spectrogram-minor-refactor

Extend column logic to peak frequency display as well, and correct some scopes according to whether values are per source column or per target pixel
author Chris Cannam
date Mon, 20 Jun 2016 12:00:32 +0100
parents d4212687520e
children b061b9f8fca5
rev   line source
Chris@224 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@224 2
Chris@224 3 /*
Chris@224 4 Sonic Visualiser
Chris@224 5 An audio file viewer and annotation editor.
Chris@224 6 Centre for Digital Music, Queen Mary, University of London.
Chris@224 7 This file copyright 2006 Chris Cannam.
Chris@224 8
Chris@224 9 This program is free software; you can redistribute it and/or
Chris@224 10 modify it under the terms of the GNU General Public License as
Chris@224 11 published by the Free Software Foundation; either version 2 of the
Chris@224 12 License, or (at your option) any later version. See the file
Chris@224 13 COPYING included with this distribution for more information.
Chris@224 14 */
Chris@224 15
Chris@224 16 #include "LogRange.h"
Chris@573 17 #include "system/System.h"
Chris@224 18
Chris@224 19 #include <algorithm>
Chris@464 20 #include <iostream>
Chris@224 21 #include <cmath>
Chris@224 22
Chris@224 23 void
Chris@1044 24 LogRange::mapRange(double &min, double &max, double logthresh)
Chris@224 25 {
Chris@224 26 if (min > max) std::swap(min, max);
Chris@224 27 if (max == min) max = min + 1;
Chris@224 28
Chris@1073 29 // cerr << "LogRange::mapRange: min = " << min << ", max = " << max << endl;
Chris@1073 30
Chris@224 31 if (min >= 0.f) {
Chris@224 32
Chris@1044 33 max = log10(max); // we know max != 0
Chris@224 34
Chris@224 35 if (min == 0.f) min = std::min(logthresh, max);
Chris@1044 36 else min = log10(min);
Chris@224 37
Chris@1073 38 // cerr << "LogRange::mapRange: positive: min = " << min << ", max = " << max << endl;
Chris@464 39
Chris@224 40 } else if (max <= 0.f) {
Chris@224 41
Chris@1044 42 min = log10(-min); // we know min != 0
Chris@224 43
Chris@224 44 if (max == 0.f) max = std::min(logthresh, min);
Chris@1044 45 else max = log10(-max);
Chris@224 46
Chris@224 47 std::swap(min, max);
Chris@224 48
Chris@1073 49 // cerr << "LogRange::mapRange: negative: min = " << min << ", max = " << max << endl;
Chris@464 50
Chris@224 51 } else {
Chris@224 52
Chris@224 53 // min < 0 and max > 0
Chris@224 54
Chris@1044 55 max = log10(std::max(max, -min));
Chris@224 56 min = std::min(logthresh, max);
Chris@464 57
Chris@1073 58 // cerr << "LogRange::mapRange: spanning: min = " << min << ", max = " << max << endl;
Chris@224 59 }
Chris@224 60
Chris@224 61 if (min == max) min = max - 1;
Chris@224 62 }
Chris@224 63
Chris@1044 64 double
Chris@1044 65 LogRange::map(double value, double thresh)
Chris@224 66 {
Chris@224 67 if (value == 0.f) return thresh;
Chris@1044 68 return log10(fabs(value));
Chris@224 69 }
Chris@224 70
Chris@1044 71 double
Chris@1044 72 LogRange::unmap(double value)
Chris@266 73 {
Chris@1044 74 return pow(10.0, value);
Chris@266 75 }
Chris@478 76
Chris@1038 77 static double
Chris@1044 78 sd(const std::vector<double> &values, int start, int n)
Chris@478 79 {
Chris@1038 80 double sum = 0.f, mean = 0.f, variance = 0.f;
Chris@1038 81 for (int i = 0; i < n; ++i) {
Chris@478 82 sum += values[start + i];
Chris@478 83 }
Chris@478 84 mean = sum / n;
Chris@1038 85 for (int i = 0; i < n; ++i) {
Chris@1038 86 double diff = values[start + i] - mean;
Chris@478 87 variance += diff * diff;
Chris@478 88 }
Chris@478 89 variance = variance / n;
Chris@1038 90 return sqrt(variance);
Chris@478 91 }
Chris@478 92
Chris@478 93 bool
Chris@1044 94 LogRange::useLogScale(std::vector<double> values)
Chris@478 95 {
Chris@478 96 // Principle: Partition the data into two sets around the median;
Chris@478 97 // calculate the standard deviation of each set; if the two SDs
Chris@478 98 // are very different, it's likely that a log scale would be good.
Chris@478 99
Chris@1038 100 int n = int(values.size());
Chris@1038 101 if (n < 4) return false;
Chris@478 102 std::sort(values.begin(), values.end());
Chris@1038 103 int mi = n / 2;
Chris@478 104
Chris@1038 105 double sd0 = sd(values, 0, mi);
Chris@1038 106 double sd1 = sd(values, mi, n - mi);
Chris@478 107
Chris@690 108 SVDEBUG << "LogRange::useLogScale: sd0 = "
Chris@687 109 << sd0 << ", sd1 = " << sd1 << endl;
Chris@478 110
Chris@478 111 if (sd0 == 0 || sd1 == 0) return false;
Chris@478 112
Chris@478 113 // I wonder what method of determining "one sd much bigger than
Chris@478 114 // the other" would be appropriate here...
Chris@1038 115 if (std::max(sd0, sd1) / std::min(sd0, sd1) > 10.) return true;
Chris@478 116 else return false;
Chris@478 117 }
Chris@478 118