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 }
|