annotate base/ColumnOp.cpp @ 1407:25ed6dde2ce0 scale-ticks

Scale tick labeller, and tests (some failing so far)
author Chris Cannam
date Wed, 03 May 2017 13:02:08 +0100
parents 9ef1cc26024c
children 1b688ab5f1b3
rev   line source
Chris@1267 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1267 2
Chris@1267 3 /*
Chris@1267 4 Sonic Visualiser
Chris@1267 5 An audio file viewer and annotation editor.
Chris@1267 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1267 7 This file copyright 2006-2016 Chris Cannam and QMUL.
Chris@1267 8
Chris@1267 9 This program is free software; you can redistribute it and/or
Chris@1267 10 modify it under the terms of the GNU General Public License as
Chris@1267 11 published by the Free Software Foundation; either version 2 of the
Chris@1267 12 License, or (at your option) any later version. See the file
Chris@1267 13 COPYING included with this distribution for more information.
Chris@1267 14 */
Chris@1267 15
Chris@1267 16 #include "ColumnOp.h"
Chris@1267 17
Chris@1267 18 #include <cmath>
Chris@1267 19 #include <algorithm>
Chris@1267 20 #include <iostream>
Chris@1267 21
Chris@1283 22 #include "base/Debug.h"
Chris@1283 23
Chris@1267 24 using namespace std;
Chris@1267 25
Chris@1267 26 ColumnOp::Column
Chris@1267 27 ColumnOp::fftScale(const Column &in, int fftSize)
Chris@1267 28 {
Chris@1267 29 return applyGain(in, 2.0 / fftSize);
Chris@1267 30 }
Chris@1267 31
Chris@1267 32 ColumnOp::Column
Chris@1267 33 ColumnOp::peakPick(const Column &in)
Chris@1267 34 {
Chris@1267 35 vector<float> out(in.size(), 0.f);
Chris@1267 36
Chris@1267 37 for (int i = 0; in_range_for(in, i); ++i) {
Chris@1267 38 if (isPeak(in, i)) {
Chris@1267 39 out[i] = in[i];
Chris@1267 40 }
Chris@1267 41 }
Chris@1267 42
Chris@1267 43 return out;
Chris@1267 44 }
Chris@1267 45
Chris@1267 46 ColumnOp::Column
Chris@1267 47 ColumnOp::normalize(const Column &in, ColumnNormalization n) {
Chris@1267 48
Chris@1267 49 if (n == ColumnNormalization::None || in.empty()) {
Chris@1267 50 return in;
Chris@1267 51 }
Chris@1394 52
Chris@1394 53 float shift = 0.f;
Chris@1394 54 float scale = 1.f;
Chris@1267 55
Chris@1394 56 if (n == ColumnNormalization::Range01) {
Chris@1394 57
Chris@1394 58 float min = 0.f;
Chris@1394 59 float max = 0.f;
Chris@1394 60 bool have = false;
Chris@1394 61 for (auto v: in) {
Chris@1394 62 if (v < min || !have) {
Chris@1394 63 min = v;
Chris@1394 64 }
Chris@1394 65 if (v > max || !have) {
Chris@1394 66 max = v;
Chris@1394 67 }
Chris@1394 68 have = true;
Chris@1394 69 }
Chris@1394 70 if (min != 0.f) {
Chris@1394 71 shift = -min;
Chris@1394 72 max -= min;
Chris@1394 73 }
Chris@1394 74 if (max != 0.f) {
Chris@1394 75 scale = 1.f / max;
Chris@1394 76 }
Chris@1394 77
Chris@1394 78 } else if (n == ColumnNormalization::Sum1) {
Chris@1267 79
Chris@1267 80 float sum = 0.f;
Chris@1267 81
Chris@1267 82 for (auto v: in) {
Chris@1267 83 sum += fabsf(v);
Chris@1267 84 }
Chris@1267 85
Chris@1267 86 if (sum != 0.f) {
Chris@1267 87 scale = 1.f / sum;
Chris@1267 88 }
Chris@1267 89
Chris@1267 90 } else {
Chris@1267 91
Chris@1267 92 float max = 0.f;
Chris@1267 93
Chris@1267 94 for (auto v: in) {
Chris@1267 95 v = fabsf(v);
Chris@1267 96 if (v > max) {
Chris@1267 97 max = v;
Chris@1267 98 }
Chris@1267 99 }
Chris@1267 100
Chris@1267 101 if (n == ColumnNormalization::Max1) {
Chris@1267 102 if (max != 0.f) {
Chris@1267 103 scale = 1.f / max;
Chris@1267 104 }
Chris@1267 105 } else if (n == ColumnNormalization::Hybrid) {
Chris@1267 106 if (max > 0.f) {
Chris@1267 107 scale = log10f(max + 1.f) / max;
Chris@1267 108 }
Chris@1267 109 }
Chris@1267 110 }
Chris@1267 111
Chris@1394 112 return applyGain(applyShift(in, shift), scale);
Chris@1267 113 }
Chris@1267 114
Chris@1267 115 ColumnOp::Column
Chris@1267 116 ColumnOp::distribute(const Column &in,
Chris@1267 117 int h,
Chris@1267 118 const vector<double> &binfory,
Chris@1267 119 int minbin,
Chris@1267 120 bool interpolate)
Chris@1267 121 {
Chris@1267 122 vector<float> out(h, 0.f);
Chris@1267 123 int bins = int(in.size());
Chris@1267 124
Chris@1303 125 if (interpolate) {
Chris@1303 126 // If the bins are all closer together than the target y
Chris@1303 127 // coordinate increments, then we don't want to interpolate
Chris@1303 128 // after all. But because the binfory mapping isn't
Chris@1303 129 // necessarily linear, just checking e.g. whether bins > h is
Chris@1303 130 // not enough -- the bins could still be spaced more widely at
Chris@1303 131 // either end of the scale. We are prepared to assume however
Chris@1303 132 // that if the bins are closer at both ends of the scale, they
Chris@1303 133 // aren't going to diverge mysteriously in the middle.
Chris@1303 134 if (h > 1 &&
Chris@1303 135 fabs(binfory[1] - binfory[0]) >= 1.0 &&
Chris@1303 136 fabs(binfory[h-1] - binfory[h-2]) >= 1.0) {
Chris@1303 137 interpolate = false;
Chris@1303 138 }
Chris@1303 139 }
Chris@1303 140
Chris@1267 141 for (int y = 0; y < h; ++y) {
Chris@1267 142
cannam@1301 143 if (interpolate) {
Chris@1267 144
Chris@1267 145 double sy = binfory[y] - minbin - 0.5;
Chris@1267 146 double syf = floor(sy);
Chris@1267 147
Chris@1267 148 int mainbin = int(syf);
Chris@1267 149 int other = mainbin;
Chris@1267 150 if (sy > syf) {
Chris@1267 151 other = mainbin + 1;
Chris@1267 152 } else if (sy < syf) {
Chris@1267 153 other = mainbin - 1;
Chris@1267 154 }
Chris@1267 155
Chris@1267 156 if (mainbin < 0) {
Chris@1267 157 mainbin = 0;
Chris@1267 158 }
Chris@1267 159 if (mainbin >= bins) {
Chris@1267 160 mainbin = bins - 1;
Chris@1267 161 }
Chris@1267 162
Chris@1267 163 if (other < 0) {
Chris@1267 164 other = 0;
Chris@1267 165 }
Chris@1267 166 if (other >= bins) {
Chris@1267 167 other = bins - 1;
Chris@1267 168 }
Chris@1267 169
Chris@1267 170 double prop = 1.0 - fabs(sy - syf);
Chris@1267 171
Chris@1267 172 double v0 = in[mainbin];
Chris@1267 173 double v1 = in[other];
Chris@1267 174
Chris@1267 175 out[y] = float(prop * v0 + (1.0 - prop) * v1);
Chris@1267 176
Chris@1267 177 } else {
Chris@1267 178
Chris@1267 179 double sy0 = binfory[y] - minbin;
Chris@1267 180
Chris@1267 181 double sy1;
Chris@1267 182 if (y+1 < h) {
Chris@1267 183 sy1 = binfory[y+1] - minbin;
Chris@1267 184 } else {
Chris@1267 185 sy1 = bins;
Chris@1267 186 }
Chris@1267 187
Chris@1267 188 int by0 = int(sy0 + 0.0001);
Chris@1267 189 int by1 = int(sy1 + 0.0001);
Chris@1283 190
Chris@1283 191 if (by0 < 0 || by0 >= bins || by1 > bins) {
Chris@1283 192 SVCERR << "ERROR: bin index out of range in ColumnOp::distribute: by0 = " << by0 << ", by1 = " << by1 << ", sy0 = " << sy0 << ", sy1 = " << sy1 << ", y = " << y << ", binfory[y] = " << binfory[y] << ", minbin = " << minbin << ", bins = " << bins << endl;
Chris@1283 193 continue;
Chris@1283 194 }
Chris@1267 195
Chris@1267 196 for (int bin = by0; bin == by0 || bin < by1; ++bin) {
Chris@1267 197
Chris@1267 198 float value = in[bin];
Chris@1267 199
Chris@1267 200 if (bin == by0 || value > out[y]) {
Chris@1267 201 out[y] = value;
Chris@1267 202 }
Chris@1267 203 }
Chris@1267 204 }
Chris@1267 205 }
Chris@1267 206
Chris@1267 207 return out;
Chris@1267 208 }