annotate base/ColumnOp.h @ 1248:58dd6a6fe414 piper

Update to use listargs variant of Piper stuff (so that the plugin winnowing feature from the penultimate commit actually works)
author Chris Cannam
date Thu, 03 Nov 2016 15:38:17 +0000
parents 6f7a440b6218
children 303039dd9e05
rev   line source
Chris@1187 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1187 2
Chris@1187 3 /*
Chris@1187 4 Sonic Visualiser
Chris@1187 5 An audio file viewer and annotation editor.
Chris@1187 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1188 7 This file copyright 2006-2016 Chris Cannam and QMUL.
Chris@1187 8
Chris@1187 9 This program is free software; you can redistribute it and/or
Chris@1187 10 modify it under the terms of the GNU General Public License as
Chris@1187 11 published by the Free Software Foundation; either version 2 of the
Chris@1187 12 License, or (at your option) any later version. See the file
Chris@1187 13 COPYING included with this distribution for more information.
Chris@1187 14 */
Chris@1187 15
Chris@1187 16 #ifndef COLUMN_OP_H
Chris@1187 17 #define COLUMN_OP_H
Chris@1187 18
Chris@1187 19 #include "BaseTypes.h"
Chris@1187 20
Chris@1187 21 #include <cmath>
Chris@1187 22
Chris@1190 23 /**
Chris@1193 24 * Display normalization types for columns in e.g. grid plots.
Chris@1193 25 *
Chris@1193 26 * Max1 means to normalize to max value = 1.0.
Chris@1193 27 * Sum1 means to normalize to sum of values = 1.0.
Chris@1193 28 *
Chris@1193 29 * Hybrid means normalize to max = 1.0 and then multiply by
Chris@1193 30 * log10 of the max value, to retain some difference between
Chris@1193 31 * levels of neighbouring columns.
Chris@1193 32 *
Chris@1193 33 * Area normalization is handled separately.
Chris@1193 34 */
Chris@1193 35 enum class ColumnNormalization {
Chris@1193 36 None,
Chris@1193 37 Max1,
Chris@1193 38 Sum1,
Chris@1193 39 Hybrid
Chris@1193 40 };
Chris@1193 41
Chris@1193 42 /**
Chris@1190 43 * Class containing static functions for simple operations on data
Chris@1190 44 * columns, for use by display layers.
Chris@1190 45 */
Chris@1187 46 class ColumnOp
Chris@1187 47 {
Chris@1187 48 public:
Chris@1190 49 /**
Chris@1190 50 * Column type.
Chris@1190 51 */
Chris@1187 52 typedef std::vector<float> Column;
Chris@1187 53
Chris@1190 54 /**
Chris@1195 55 * Scale the given column using the given gain multiplier.
Chris@1195 56 */
Chris@1197 57 static Column applyGain(const Column &in, double gain) {
Chris@1195 58
Chris@1197 59 if (gain == 1.0) {
Chris@1195 60 return in;
Chris@1195 61 }
Chris@1195 62 Column out;
Chris@1195 63 out.reserve(in.size());
Chris@1195 64 for (auto v: in) {
Chris@1197 65 out.push_back(float(v * gain));
Chris@1195 66 }
Chris@1195 67 return out;
Chris@1195 68 }
Chris@1195 69
Chris@1195 70 /**
Chris@1190 71 * Scale an FFT output by half the FFT size.
Chris@1190 72 */
Chris@1187 73 static Column fftScale(const Column &in, int fftSize) {
Chris@1197 74 return applyGain(in, 2.0 / fftSize);
Chris@1187 75 }
Chris@1187 76
Chris@1190 77 /**
Chris@1190 78 * Determine whether an index points to a local peak.
Chris@1190 79 */
Chris@1187 80 static bool isPeak(const Column &in, int ix) {
Chris@1187 81
Chris@1187 82 if (!in_range_for(in, ix-1)) return false;
Chris@1187 83 if (!in_range_for(in, ix+1)) return false;
Chris@1187 84 if (in[ix] < in[ix+1]) return false;
Chris@1187 85 if (in[ix] < in[ix-1]) return false;
Chris@1187 86
Chris@1187 87 return true;
Chris@1187 88 }
Chris@1187 89
Chris@1190 90 /**
Chris@1190 91 * Return a column containing only the local peak values (all
Chris@1190 92 * others zero).
Chris@1190 93 */
Chris@1187 94 static Column peakPick(const Column &in) {
Chris@1187 95
Chris@1187 96 std::vector<float> out(in.size(), 0.f);
Chris@1187 97 for (int i = 0; in_range_for(in, i); ++i) {
Chris@1187 98 if (isPeak(in, i)) {
Chris@1187 99 out[i] = in[i];
Chris@1187 100 }
Chris@1187 101 }
Chris@1187 102
Chris@1187 103 return out;
Chris@1187 104 }
Chris@1187 105
Chris@1190 106 /**
Chris@1190 107 * Return a column normalized from the input column according to
Chris@1190 108 * the given normalization scheme.
Chris@1190 109 */
Chris@1193 110 static Column normalize(const Column &in, ColumnNormalization n) {
Chris@1187 111
Chris@1193 112 if (n == ColumnNormalization::None) {
Chris@1187 113 return in;
Chris@1187 114 }
Chris@1187 115
Chris@1193 116 float scale = 1.f;
Chris@1193 117
Chris@1193 118 if (n == ColumnNormalization::Sum1) {
Chris@1193 119
Chris@1193 120 float sum = 0.f;
Chris@1193 121
Chris@1193 122 for (auto v: in) {
Chris@1193 123 sum += v;
Chris@1193 124 }
Chris@1193 125
Chris@1193 126 if (sum != 0.f) {
Chris@1193 127 scale = 1.f / sum;
Chris@1193 128 }
Chris@1193 129 } else {
Chris@1193 130
Chris@1193 131 float max = *max_element(in.begin(), in.end());
Chris@1193 132
Chris@1193 133 if (n == ColumnNormalization::Max1) {
Chris@1193 134 if (max != 0.f) {
Chris@1193 135 scale = 1.f / max;
Chris@1193 136 }
Chris@1193 137 } else if (n == ColumnNormalization::Hybrid) {
Chris@1193 138 if (max > 0.f) {
Chris@1193 139 scale = log10f(max + 1.f) / max;
Chris@1193 140 }
Chris@1193 141 }
Chris@1193 142 }
Chris@1187 143
Chris@1197 144 return applyGain(in, scale);
Chris@1187 145 }
Chris@1187 146
Chris@1190 147 /**
Chris@1190 148 * Distribute the given column into a target vector of a different
Chris@1190 149 * size, optionally using linear interpolation. The binfory vector
Chris@1190 150 * contains a mapping from y coordinate (i.e. index into the
Chris@1190 151 * target vector) to bin (i.e. index into the source column).
Chris@1190 152 */
Chris@1187 153 static Column distribute(const Column &in,
Chris@1187 154 int h,
Chris@1187 155 const std::vector<double> &binfory,
Chris@1187 156 int minbin,
Chris@1187 157 bool interpolate) {
Chris@1198 158
Chris@1187 159 std::vector<float> out(h, 0.f);
Chris@1187 160 int bins = int(in.size());
Chris@1187 161
Chris@1187 162 for (int y = 0; y < h; ++y) {
Chris@1187 163
Chris@1187 164 double sy0 = binfory[y] - minbin;
Chris@1187 165 double sy1 = sy0 + 1;
Chris@1187 166 if (y+1 < h) {
Chris@1187 167 sy1 = binfory[y+1] - minbin;
Chris@1187 168 }
Chris@1187 169
Chris@1187 170 if (interpolate && fabs(sy1 - sy0) < 1.0) {
Chris@1187 171
Chris@1187 172 double centre = (sy0 + sy1) / 2;
Chris@1187 173 double dist = (centre - 0.5) - rint(centre - 0.5);
Chris@1187 174 int bin = int(centre);
Chris@1187 175
Chris@1187 176 int other = (dist < 0 ? (bin-1) : (bin+1));
Chris@1187 177
Chris@1187 178 if (bin < 0) bin = 0;
Chris@1187 179 if (bin >= bins) bin = bins-1;
Chris@1187 180
Chris@1187 181 if (other < 0 || other >= bins) {
Chris@1187 182 other = bin;
Chris@1187 183 }
Chris@1187 184
Chris@1187 185 double prop = 1.0 - fabs(dist);
Chris@1187 186
Chris@1187 187 double v0 = in[bin];
Chris@1187 188 double v1 = in[other];
Chris@1187 189
Chris@1187 190 out[y] = float(prop * v0 + (1.0 - prop) * v1);
Chris@1187 191
Chris@1187 192 } else { // not interpolating this one
Chris@1187 193
Chris@1187 194 int by0 = int(sy0 + 0.0001);
Chris@1187 195 int by1 = int(sy1 + 0.0001);
Chris@1187 196 if (by1 < by0 + 1) by1 = by0 + 1;
Chris@1198 197 if (by1 >= bins) by1 = by1 - 1;
Chris@1198 198
Chris@1187 199 for (int bin = by0; bin < by1; ++bin) {
Chris@1187 200
Chris@1187 201 float value = in[bin];
Chris@1187 202
Chris@1201 203 if (bin == by0 || value > out[y]) {
Chris@1187 204 out[y] = value;
Chris@1187 205 }
Chris@1187 206 }
Chris@1187 207 }
Chris@1187 208 }
Chris@1187 209
Chris@1187 210 return out;
Chris@1187 211 }
Chris@1187 212
Chris@1187 213 };
Chris@1187 214
Chris@1187 215 #endif
Chris@1187 216