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