Chris@35
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@35
|
2
|
Chris@42
|
3 /*
|
Chris@42
|
4 Tipic
|
Chris@42
|
5
|
Chris@42
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@42
|
7
|
Chris@42
|
8 This program is free software; you can redistribute it and/or
|
Chris@42
|
9 modify it under the terms of the GNU General Public License as
|
Chris@42
|
10 published by the Free Software Foundation; either version 2 of the
|
Chris@42
|
11 License, or (at your option) any later version. See the file
|
Chris@42
|
12 COPYING included with this distribution for more information.
|
Chris@42
|
13 */
|
Chris@42
|
14
|
Chris@35
|
15 #include "FeatureDownsample.h"
|
Chris@35
|
16
|
Chris@42
|
17 #include "dsp/signalconditioning/Filter.h"
|
Chris@42
|
18 #include "base/Window.h"
|
Chris@42
|
19 #include "maths/MathUtilities.h"
|
Chris@35
|
20
|
Chris@35
|
21 #include <stdexcept>
|
Chris@35
|
22
|
Chris@35
|
23 using namespace std;
|
Chris@35
|
24
|
Chris@35
|
25 FeatureDownsample::FeatureDownsample(Parameters params) :
|
Chris@35
|
26 m_params(params)
|
Chris@35
|
27 {
|
Chris@35
|
28 if (params.downsampleFactor < 2 || params.windowLength < 2) {
|
Chris@35
|
29 throw invalid_argument
|
Chris@35
|
30 ("Expected downsampleFactor and windowLength each to be at least 2");
|
Chris@35
|
31 }
|
Chris@35
|
32
|
Chris@35
|
33 // Our windows are periodic rather than symmetric, but we want a
|
Chris@35
|
34 // symmetric window here
|
Chris@37
|
35 Window<double> w(HanningWindow, params.windowLength + 1);
|
Chris@37
|
36 vector<double> wdat(w.getWindowData());;
|
Chris@37
|
37 vector<double> wd(wdat.begin()+1, wdat.end());
|
Chris@35
|
38
|
Chris@36
|
39 double divisor = 0.0;
|
Chris@36
|
40 for (auto x: wd) divisor += x;
|
Chris@36
|
41 for (auto &x: wd) x /= divisor;
|
Chris@36
|
42
|
Chris@35
|
43 // FIR filter
|
Chris@35
|
44 for (int i = 0; i < m_params.featureSize; ++i) {
|
Chris@35
|
45 m_filters.push_back(new Filter({ {}, wd }));
|
Chris@35
|
46 }
|
Chris@35
|
47
|
Chris@36
|
48 m_toNext = 1;
|
Chris@36
|
49 m_toDrop = m_params.windowLength / 2;
|
Chris@36
|
50 m_inCount = 0;
|
Chris@36
|
51 m_outCount = 0;
|
Chris@35
|
52 }
|
Chris@35
|
53
|
Chris@35
|
54 FeatureDownsample::~FeatureDownsample()
|
Chris@35
|
55 {
|
Chris@35
|
56 for (auto &f: m_filters) delete f;
|
Chris@35
|
57 }
|
Chris@35
|
58
|
Chris@35
|
59 void
|
Chris@35
|
60 FeatureDownsample::reset()
|
Chris@35
|
61 {
|
Chris@35
|
62 for (auto &f: m_filters) f->reset();
|
Chris@36
|
63 m_toNext = 1;
|
Chris@36
|
64 m_toDrop = m_params.windowLength / 2;
|
Chris@36
|
65 m_inCount = 0;
|
Chris@36
|
66 m_outCount = 0;
|
Chris@35
|
67 }
|
Chris@35
|
68
|
Chris@35
|
69 RealBlock
|
Chris@35
|
70 FeatureDownsample::process(const RealBlock &in)
|
Chris@35
|
71 {
|
Chris@36
|
72 RealBlock out;
|
Chris@35
|
73
|
Chris@35
|
74 for (const auto &col: in) {
|
Chris@35
|
75 RealColumn outcol;
|
Chris@36
|
76 if (m_toDrop > 0) {
|
Chris@36
|
77 --m_toDrop;
|
Chris@36
|
78 } else {
|
Chris@36
|
79 --m_toNext;
|
Chris@36
|
80 }
|
Chris@35
|
81 for (int i = 0; i < m_params.featureSize; ++i) {
|
Chris@35
|
82 double val = 0.0;
|
Chris@35
|
83 m_filters[i]->process(&col[i], &val, 1);
|
Chris@35
|
84 if (m_toNext == 0) {
|
Chris@35
|
85 outcol.push_back(val);
|
Chris@35
|
86 }
|
Chris@35
|
87 }
|
Chris@35
|
88 if (m_toNext == 0) {
|
Chris@42
|
89 out.push_back(MathUtilities::normaliseLp
|
Chris@37
|
90 (outcol, m_params.normP, m_params.normThresh));
|
Chris@35
|
91 m_toNext = m_params.downsampleFactor;
|
Chris@36
|
92 ++m_outCount;
|
Chris@35
|
93 }
|
Chris@36
|
94 ++m_inCount;
|
Chris@36
|
95 }
|
Chris@36
|
96
|
Chris@36
|
97 return out;
|
Chris@36
|
98 }
|
Chris@36
|
99
|
Chris@36
|
100 RealBlock
|
Chris@36
|
101 FeatureDownsample::getRemainingOutput()
|
Chris@36
|
102 {
|
Chris@36
|
103 RealBlock pad(m_params.windowLength, RealColumn(m_params.featureSize, 0.0));
|
Chris@36
|
104 RealBlock tail = process(pad);
|
Chris@36
|
105 int expected = m_inCount / m_params.downsampleFactor;
|
Chris@36
|
106 RealBlock out;
|
Chris@36
|
107 for (int i = 0;
|
Chris@36
|
108 m_outCount < expected && i < int(tail.size());
|
Chris@36
|
109 ++i, ++m_outCount) {
|
Chris@42
|
110 out.push_back(MathUtilities::normaliseLp
|
Chris@37
|
111 (tail[i], m_params.normP, m_params.normThresh));
|
Chris@35
|
112 }
|
Chris@35
|
113 return out;
|
Chris@35
|
114 }
|
Chris@35
|
115
|
Chris@36
|
116
|