comparison dsp/rateconversion/Resampler.cpp @ 145:fe267879e022

Avoid vector reallocation on every reconstructed output sample
author Chris Cannam
date Wed, 16 Oct 2013 13:33:18 +0100
parents a4aa37f7af28
children 235b99c7d4ce
comparison
equal deleted inserted replaced
144:b21e97d570be 145:fe267879e022
6 #include "qm-dsp/base/KaiserWindow.h" 6 #include "qm-dsp/base/KaiserWindow.h"
7 #include "qm-dsp/base/SincWindow.h" 7 #include "qm-dsp/base/SincWindow.h"
8 8
9 #include <iostream> 9 #include <iostream>
10 #include <vector> 10 #include <vector>
11 #include <map>
11 12
12 using std::vector; 13 using std::vector;
14 using std::map;
13 15
14 //#define DEBUG_RESAMPLER 1 16 //#define DEBUG_RESAMPLER 1
15 17
16 Resampler::Resampler(int sourceRate, int targetRate) : 18 Resampler::Resampler(int sourceRate, int targetRate) :
17 m_sourceRate(sourceRate), 19 m_sourceRate(sourceRate),
40 42
41 params.length = 43 params.length =
42 (params.length % 2 == 0 ? params.length + 1 : params.length); 44 (params.length % 2 == 0 ? params.length + 1 : params.length);
43 45
44 m_filterLength = params.length; 46 m_filterLength = params.length;
45 47
46 std::cerr << "making filter... ";
47 KaiserWindow kw(params); 48 KaiserWindow kw(params);
48 SincWindow sw(m_filterLength, peakToPole * 2); 49 SincWindow sw(m_filterLength, peakToPole * 2);
49 std::cerr << "done" << std::endl; 50
50 51 vector<double> filter(m_filterLength, 0.0);
51 double *filter = new double[m_filterLength];
52 for (int i = 0; i < m_filterLength; ++i) filter[i] = 1.0; 52 for (int i = 0; i < m_filterLength; ++i) filter[i] = 1.0;
53 sw.cut(filter); 53 sw.cut(filter.data());
54 kw.cut(filter); 54 kw.cut(filter.data());
55 55
56 int inputSpacing = m_targetRate / m_gcd; 56 int inputSpacing = m_targetRate / m_gcd;
57 int outputSpacing = m_sourceRate / m_gcd; 57 int outputSpacing = m_sourceRate / m_gcd;
58 58
59 #ifdef DEBUG_RESAMPLER 59 #ifdef DEBUG_RESAMPLER
82 p.filter.push_back(filter[i * inputSpacing + phase]); 82 p.filter.push_back(filter[i * inputSpacing + phase]);
83 } 83 }
84 84
85 m_phaseData[phase] = p; 85 m_phaseData[phase] = p;
86 } 86 }
87
88 #ifdef DEBUG_RESAMPLER
89 for (int phase = 0; phase < inputSpacing; ++phase) {
90 std::cerr << "filter for phase " << phase << " of " << inputSpacing << " (with length " << m_phaseData[phase].filter.size() << "):";
91 for (int i = 0; i < m_phaseData[phase].filter.size(); ++i) {
92 if (i % 4 == 0) {
93 std::cerr << std::endl << i << ": ";
94 }
95 float v = m_phaseData[phase].filter[i];
96 if (v == 1) {
97 std::cerr << " *** " << v << " *** ";
98 } else {
99 std::cerr << v << " ";
100 }
101 }
102 std::cerr << std::endl;
103 }
104 #endif
105
106 delete[] filter;
107 87
108 // The May implementation of this uses a pull model -- we ask the 88 // The May implementation of this uses a pull model -- we ask the
109 // resampler for a certain number of output samples, and it asks 89 // resampler for a certain number of output samples, and it asks
110 // its source stream for as many as it needs to calculate 90 // its source stream for as many as it needs to calculate
111 // those. This means (among other things) that the source stream 91 // those. This means (among other things) that the source stream
123 // latter. (What do other implementations do?) 103 // latter. (What do other implementations do?)
124 104
125 m_phase = (m_filterLength/2) % inputSpacing; 105 m_phase = (m_filterLength/2) % inputSpacing;
126 106
127 m_buffer = vector<double>(m_phaseData[0].filter.size(), 0); 107 m_buffer = vector<double>(m_phaseData[0].filter.size(), 0);
108 m_bufferOrigin = 0;
128 109
129 m_latency = 110 m_latency =
130 ((m_buffer.size() * inputSpacing) - (m_filterLength/2)) / outputSpacing 111 ((m_buffer.size() * inputSpacing) - (m_filterLength/2)) / outputSpacing
131 + m_phase; 112 + m_phase;
132 113
140 Resampler::reconstructOne() 121 Resampler::reconstructOne()
141 { 122 {
142 Phase &pd = m_phaseData[m_phase]; 123 Phase &pd = m_phaseData[m_phase];
143 double v = 0.0; 124 double v = 0.0;
144 int n = pd.filter.size(); 125 int n = pd.filter.size();
145 const double *buf = m_buffer.data(); 126 const double *const __restrict__ buf = m_buffer.data() + m_bufferOrigin;
146 const double *filt = pd.filter.data(); 127 const double *const __restrict__ filt = pd.filter.data();
147 for (int i = 0; i < n; ++i) { 128 for (int i = 0; i < n; ++i) {
148 v += buf[i] * filt[i]; //!!! gcc can't vectorize: why? 129 // NB gcc can only vectorize this with -ffast-math
149 } 130 v += buf[i] * filt[i];
150 m_buffer = vector<double>(m_buffer.begin() + pd.drop, m_buffer.end()); 131 }
132 m_bufferOrigin += pd.drop;
151 m_phase = pd.nextPhase; 133 m_phase = pd.nextPhase;
152 return v; 134 return v;
153 } 135 }
154 136
155 int 137 int
169 double scaleFactor = 1.0; 151 double scaleFactor = 1.0;
170 if (m_targetRate < m_sourceRate) { 152 if (m_targetRate < m_sourceRate) {
171 scaleFactor = double(m_targetRate) / double(m_sourceRate); 153 scaleFactor = double(m_targetRate) / double(m_sourceRate);
172 } 154 }
173 155
174 std::cerr << "maxout = " << maxout << std::endl;
175
176 while (outidx < maxout && 156 while (outidx < maxout &&
177 m_buffer.size() >= m_phaseData[m_phase].filter.size()) { 157 m_buffer.size() >= m_phaseData[m_phase].filter.size() + m_bufferOrigin) {
178 dst[outidx] = scaleFactor * reconstructOne(); 158 dst[outidx] = scaleFactor * reconstructOne();
179 outidx++; 159 outidx++;
180 } 160 }
161
162 m_buffer = vector<double>(m_buffer.begin() + m_bufferOrigin, m_buffer.end());
163 m_bufferOrigin = 0;
181 164
182 return outidx; 165 return outidx;
183 } 166 }
184 167
185 std::vector<double> 168 std::vector<double>
193 // padding input samples at the end of input to guarantee at 176 // padding input samples at the end of input to guarantee at
194 // *least* the latency's worth of output samples. that is, 177 // *least* the latency's worth of output samples. that is,
195 178
196 int inputPad = int(ceil(double(latency * sourceRate) / targetRate)); 179 int inputPad = int(ceil(double(latency * sourceRate) / targetRate));
197 180
198 std::cerr << "latency = " << latency << ", inputPad = " << inputPad << std::endl;
199
200 // that means we are providing this much input in total: 181 // that means we are providing this much input in total:
201 182
202 int n1 = n + inputPad; 183 int n1 = n + inputPad;
203 184
204 // and obtaining this much output in total: 185 // and obtaining this much output in total:
207 188
208 // in order to return this much output to the user: 189 // in order to return this much output to the user:
209 190
210 int m = int(ceil(double(n * targetRate) / sourceRate)); 191 int m = int(ceil(double(n * targetRate) / sourceRate));
211 192
212 std::cerr << "n = " << n << ", sourceRate = " << sourceRate << ", targetRate = " << targetRate << ", m = " << m << ", latency = " << latency << ", m1 = " << m1 << ", n1 = " << n1 << ", n1 - n = " << n1 - n << std::endl; 193 // std::cerr << "n = " << n << ", sourceRate = " << sourceRate << ", targetRate = " << targetRate << ", m = " << m << ", latency = " << latency << ", m1 = " << m1 << ", n1 = " << n1 << ", n1 - n = " << n1 - n << std::endl;
213 194
214 vector<double> pad(n1 - n, 0.0); 195 vector<double> pad(n1 - n, 0.0);
215 vector<double> out(m1 + 1, 0.0); 196 vector<double> out(m1 + 1, 0.0);
216 197
217 int got = r.process(data, out.data(), n); 198 int got = r.process(data, out.data(), n);