Mercurial > hg > qm-dsp
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); |
