annotate base/ColumnOp.h @ 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 fd40a5335968
children f6998e304b36
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@1187 23 class ColumnOp
Chris@1187 24 {
Chris@1187 25 public:
Chris@1187 26 typedef std::vector<float> Column;
Chris@1187 27
Chris@1187 28 enum Normalization {
Chris@1187 29 NoNormalization,
Chris@1187 30 NormalizeColumns,
Chris@1187 31 NormalizeVisibleArea,
Chris@1187 32 NormalizeHybrid
Chris@1187 33 };
Chris@1187 34
Chris@1187 35 static Column fftScale(const Column &in, int fftSize) {
Chris@1187 36
Chris@1187 37 Column out;
Chris@1187 38 out.reserve(in.size());
Chris@1187 39 float scale = 2.f / float(fftSize);
Chris@1187 40 for (auto v: in) {
Chris@1187 41 out.push_back(v * scale);
Chris@1187 42 }
Chris@1187 43
Chris@1187 44 return out;
Chris@1187 45 }
Chris@1187 46
Chris@1187 47 static bool isPeak(const Column &in, int ix) {
Chris@1187 48
Chris@1187 49 if (!in_range_for(in, ix-1)) return false;
Chris@1187 50 if (!in_range_for(in, ix+1)) return false;
Chris@1187 51 if (in[ix] < in[ix+1]) return false;
Chris@1187 52 if (in[ix] < in[ix-1]) return false;
Chris@1187 53
Chris@1187 54 return true;
Chris@1187 55 }
Chris@1187 56
Chris@1187 57 static Column peakPick(const Column &in) {
Chris@1187 58
Chris@1187 59 std::vector<float> out(in.size(), 0.f);
Chris@1187 60 for (int i = 0; in_range_for(in, i); ++i) {
Chris@1187 61 if (isPeak(in, i)) {
Chris@1187 62 out[i] = in[i];
Chris@1187 63 }
Chris@1187 64 }
Chris@1187 65
Chris@1187 66 return out;
Chris@1187 67 }
Chris@1187 68
Chris@1187 69 static Column normalize(const Column &in, Normalization n) {
Chris@1187 70
Chris@1187 71 if (n == NoNormalization || n == NormalizeVisibleArea) {
Chris@1187 72 return in;
Chris@1187 73 }
Chris@1187 74
Chris@1187 75 float max = *max_element(in.begin(), in.end());
Chris@1187 76
Chris@1187 77 if (n == NormalizeColumns && max == 0.f) {
Chris@1187 78 return in;
Chris@1187 79 }
Chris@1187 80
Chris@1187 81 if (n == NormalizeHybrid && max <= 0.f) {
Chris@1187 82 return in;
Chris@1187 83 }
Chris@1187 84
Chris@1187 85 std::vector<float> out;
Chris@1187 86 out.reserve(in.size());
Chris@1187 87
Chris@1187 88 float scale;
Chris@1187 89 if (n == NormalizeHybrid) {
Chris@1187 90 scale = log10f(max + 1.f) / max;
Chris@1187 91 } else {
Chris@1187 92 scale = 1.f / max;
Chris@1187 93 }
Chris@1187 94
Chris@1187 95 for (auto v: in) {
Chris@1187 96 out.push_back(v * scale);
Chris@1187 97 }
Chris@1187 98 return out;
Chris@1187 99 }
Chris@1187 100
Chris@1187 101 static Column applyGain(const Column &in, float gain) {
Chris@1187 102
Chris@1187 103 if (gain == 1.f) {
Chris@1187 104 return in;
Chris@1187 105 }
Chris@1187 106 Column out;
Chris@1187 107 out.reserve(in.size());
Chris@1187 108 for (auto v: in) {
Chris@1187 109 out.push_back(v * gain);
Chris@1187 110 }
Chris@1187 111 return out;
Chris@1187 112 }
Chris@1187 113
Chris@1187 114 static Column distribute(const Column &in,
Chris@1187 115 int h,
Chris@1187 116 const std::vector<double> &binfory,
Chris@1187 117 int minbin,
Chris@1187 118 bool interpolate) {
Chris@1187 119
Chris@1187 120 std::vector<float> out(h, 0.f);
Chris@1187 121 int bins = int(in.size());
Chris@1187 122
Chris@1187 123 for (int y = 0; y < h; ++y) {
Chris@1187 124
Chris@1187 125 double sy0 = binfory[y] - minbin;
Chris@1187 126 double sy1 = sy0 + 1;
Chris@1187 127 if (y+1 < h) {
Chris@1187 128 sy1 = binfory[y+1] - minbin;
Chris@1187 129 }
Chris@1187 130
Chris@1187 131 if (interpolate && fabs(sy1 - sy0) < 1.0) {
Chris@1187 132
Chris@1187 133 double centre = (sy0 + sy1) / 2;
Chris@1187 134 double dist = (centre - 0.5) - rint(centre - 0.5);
Chris@1187 135 int bin = int(centre);
Chris@1187 136
Chris@1187 137 int other = (dist < 0 ? (bin-1) : (bin+1));
Chris@1187 138
Chris@1187 139 if (bin < 0) bin = 0;
Chris@1187 140 if (bin >= bins) bin = bins-1;
Chris@1187 141
Chris@1187 142 if (other < 0 || other >= bins) {
Chris@1187 143 other = bin;
Chris@1187 144 }
Chris@1187 145
Chris@1187 146 double prop = 1.0 - fabs(dist);
Chris@1187 147
Chris@1187 148 double v0 = in[bin];
Chris@1187 149 double v1 = in[other];
Chris@1187 150
Chris@1187 151 out[y] = float(prop * v0 + (1.0 - prop) * v1);
Chris@1187 152
Chris@1187 153 } else { // not interpolating this one
Chris@1187 154
Chris@1187 155 int by0 = int(sy0 + 0.0001);
Chris@1187 156 int by1 = int(sy1 + 0.0001);
Chris@1187 157 if (by1 < by0 + 1) by1 = by0 + 1;
Chris@1187 158
Chris@1187 159 for (int bin = by0; bin < by1; ++bin) {
Chris@1187 160
Chris@1187 161 float value = in[bin];
Chris@1187 162
Chris@1187 163 if (value > out[y]) {
Chris@1187 164 out[y] = value;
Chris@1187 165 }
Chris@1187 166 }
Chris@1187 167 }
Chris@1187 168 }
Chris@1187 169
Chris@1187 170 return out;
Chris@1187 171 }
Chris@1187 172
Chris@1187 173 };
Chris@1187 174
Chris@1187 175 #endif
Chris@1187 176