annotate base/ColumnOp.cpp @ 1394:9ef1cc26024c

Add Range01 normalisation method to ColumnOp. This is the normalisation that is actually used in the Colour 3D Plot layer historically when column normalisation is enabled (not Max1 after all).
author Chris Cannam
date Tue, 28 Feb 2017 14:04:16 +0000
parents 47ee4706055c
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 }