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@1267
|
52
|
Chris@1267
|
53 float scale = 1.f;
|
Chris@1267
|
54
|
Chris@1267
|
55 if (n == ColumnNormalization::Sum1) {
|
Chris@1267
|
56
|
Chris@1267
|
57 float sum = 0.f;
|
Chris@1267
|
58
|
Chris@1267
|
59 for (auto v: in) {
|
Chris@1267
|
60 sum += fabsf(v);
|
Chris@1267
|
61 }
|
Chris@1267
|
62
|
Chris@1267
|
63 if (sum != 0.f) {
|
Chris@1267
|
64 scale = 1.f / sum;
|
Chris@1267
|
65 }
|
Chris@1267
|
66
|
Chris@1267
|
67 } else {
|
Chris@1267
|
68
|
Chris@1267
|
69 float max = 0.f;
|
Chris@1267
|
70
|
Chris@1267
|
71 for (auto v: in) {
|
Chris@1267
|
72 v = fabsf(v);
|
Chris@1267
|
73 if (v > max) {
|
Chris@1267
|
74 max = v;
|
Chris@1267
|
75 }
|
Chris@1267
|
76 }
|
Chris@1267
|
77
|
Chris@1267
|
78 if (n == ColumnNormalization::Max1) {
|
Chris@1267
|
79 if (max != 0.f) {
|
Chris@1267
|
80 scale = 1.f / max;
|
Chris@1267
|
81 }
|
Chris@1267
|
82 } else if (n == ColumnNormalization::Hybrid) {
|
Chris@1267
|
83 if (max > 0.f) {
|
Chris@1267
|
84 scale = log10f(max + 1.f) / max;
|
Chris@1267
|
85 }
|
Chris@1267
|
86 }
|
Chris@1267
|
87 }
|
Chris@1267
|
88
|
Chris@1267
|
89 return applyGain(in, scale);
|
Chris@1267
|
90 }
|
Chris@1267
|
91
|
Chris@1267
|
92 ColumnOp::Column
|
Chris@1267
|
93 ColumnOp::distribute(const Column &in,
|
Chris@1267
|
94 int h,
|
Chris@1267
|
95 const vector<double> &binfory,
|
Chris@1267
|
96 int minbin,
|
Chris@1267
|
97 bool interpolate)
|
Chris@1267
|
98 {
|
Chris@1267
|
99 vector<float> out(h, 0.f);
|
Chris@1267
|
100 int bins = int(in.size());
|
Chris@1267
|
101
|
Chris@1267
|
102 for (int y = 0; y < h; ++y) {
|
Chris@1267
|
103
|
cannam@1301
|
104 if (interpolate) {
|
Chris@1267
|
105
|
Chris@1267
|
106 double sy = binfory[y] - minbin - 0.5;
|
Chris@1267
|
107 double syf = floor(sy);
|
Chris@1267
|
108
|
Chris@1267
|
109 int mainbin = int(syf);
|
Chris@1267
|
110 int other = mainbin;
|
Chris@1267
|
111 if (sy > syf) {
|
Chris@1267
|
112 other = mainbin + 1;
|
Chris@1267
|
113 } else if (sy < syf) {
|
Chris@1267
|
114 other = mainbin - 1;
|
Chris@1267
|
115 }
|
Chris@1267
|
116
|
Chris@1267
|
117 if (mainbin < 0) {
|
Chris@1267
|
118 mainbin = 0;
|
Chris@1267
|
119 }
|
Chris@1267
|
120 if (mainbin >= bins) {
|
Chris@1267
|
121 mainbin = bins - 1;
|
Chris@1267
|
122 }
|
Chris@1267
|
123
|
Chris@1267
|
124 if (other < 0) {
|
Chris@1267
|
125 other = 0;
|
Chris@1267
|
126 }
|
Chris@1267
|
127 if (other >= bins) {
|
Chris@1267
|
128 other = bins - 1;
|
Chris@1267
|
129 }
|
Chris@1267
|
130
|
Chris@1267
|
131 double prop = 1.0 - fabs(sy - syf);
|
Chris@1267
|
132
|
Chris@1267
|
133 double v0 = in[mainbin];
|
Chris@1267
|
134 double v1 = in[other];
|
Chris@1267
|
135
|
Chris@1267
|
136 out[y] = float(prop * v0 + (1.0 - prop) * v1);
|
Chris@1267
|
137
|
Chris@1267
|
138 } else {
|
Chris@1267
|
139
|
Chris@1267
|
140 double sy0 = binfory[y] - minbin;
|
Chris@1267
|
141
|
Chris@1267
|
142 double sy1;
|
Chris@1267
|
143 if (y+1 < h) {
|
Chris@1267
|
144 sy1 = binfory[y+1] - minbin;
|
Chris@1267
|
145 } else {
|
Chris@1267
|
146 sy1 = bins;
|
Chris@1267
|
147 }
|
Chris@1267
|
148
|
Chris@1267
|
149 int by0 = int(sy0 + 0.0001);
|
Chris@1267
|
150 int by1 = int(sy1 + 0.0001);
|
Chris@1283
|
151
|
Chris@1283
|
152 if (by0 < 0 || by0 >= bins || by1 > bins) {
|
Chris@1283
|
153 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
|
154 continue;
|
Chris@1283
|
155 }
|
Chris@1267
|
156
|
Chris@1267
|
157 for (int bin = by0; bin == by0 || bin < by1; ++bin) {
|
Chris@1267
|
158
|
Chris@1267
|
159 float value = in[bin];
|
Chris@1267
|
160
|
Chris@1267
|
161 if (bin == by0 || value > out[y]) {
|
Chris@1267
|
162 out[y] = value;
|
Chris@1267
|
163 }
|
Chris@1267
|
164 }
|
Chris@1267
|
165 }
|
Chris@1267
|
166 }
|
Chris@1267
|
167
|
Chris@1267
|
168 return out;
|
Chris@1267
|
169 }
|