Mercurial > hg > sonic-visualiser
comparison audioio/PhaseVocoderTimeStretcher.cpp @ 16:3715efc38f95
* substantial enhancements to time stretcher:
-- use putInput/getOutput methods to ensure the audio source always feeds
it enough input, avoiding underruns due to rounding error
-- add a percussion detector and an optional "Sharpen" toggle to the main
window, which invokes a very basic variable speed timestretcher
author | Chris Cannam |
---|---|
date | Wed, 13 Sep 2006 17:17:42 +0000 |
parents | cc566264c935 |
children | 67d54627efd3 |
comparison
equal
deleted
inserted
replaced
15:cc566264c935 | 16:3715efc38f95 |
---|---|
18 #include <iostream> | 18 #include <iostream> |
19 #include <cassert> | 19 #include <cassert> |
20 | 20 |
21 //#define DEBUG_PHASE_VOCODER_TIME_STRETCHER 1 | 21 //#define DEBUG_PHASE_VOCODER_TIME_STRETCHER 1 |
22 | 22 |
23 PhaseVocoderTimeStretcher::PhaseVocoderTimeStretcher(float ratio, | 23 PhaseVocoderTimeStretcher::PhaseVocoderTimeStretcher(size_t channels, |
24 float ratio, | |
25 bool sharpen, | |
24 size_t maxProcessInputBlockSize) : | 26 size_t maxProcessInputBlockSize) : |
25 m_ratio(ratio) | 27 m_channels(channels), |
26 //, | 28 m_ratio(ratio), |
27 // m_n1(inputIncrement), | 29 m_sharpen(sharpen) |
28 // m_n2(lrintf(m_n1 * ratio)), | 30 { |
29 // m_wlen(std::max(windowSize, m_n2 * 2)), | 31 m_wlen = 1024; |
30 // m_inbuf(m_wlen), | 32 |
31 // m_outbuf(maxProcessInputBlockSize * ratio + 1024) //!!! | |
32 { | |
33 if (ratio < 1) { | 33 if (ratio < 1) { |
34 m_n1 = 512; | 34 if (ratio < 0.4) { |
35 m_n1 = 1024; | |
36 m_wlen = 2048; | |
37 } else if (ratio < 0.8) { | |
38 m_n1 = 512; | |
39 } else { | |
40 m_n1 = 256; | |
41 } | |
42 if (m_sharpen) { | |
43 m_n1 /= 2; | |
44 m_wlen = 2048; | |
45 } | |
35 m_n2 = m_n1 * ratio; | 46 m_n2 = m_n1 * ratio; |
36 m_wlen = 1024; | |
37 } else { | 47 } else { |
38 m_n2 = 512; | 48 if (ratio > 2) { |
49 m_n2 = 512; | |
50 m_wlen = 4096; | |
51 } else if (ratio > 1.6) { | |
52 m_n2 = 384; | |
53 m_wlen = 2048; | |
54 } else { | |
55 m_n2 = 256; | |
56 } | |
57 if (m_sharpen) { | |
58 m_n2 /= 2; | |
59 if (m_wlen < 2048) m_wlen = 2048; | |
60 } | |
39 m_n1 = m_n2 / ratio; | 61 m_n1 = m_n2 / ratio; |
40 m_wlen = 1024; | 62 } |
41 } | 63 |
42 | 64 m_window = new Window<float>(HanningWindow, m_wlen); |
43 m_inbuf = new RingBuffer<float>(m_wlen); | 65 |
44 m_outbuf = new RingBuffer<float> | 66 m_prevPhase = new float *[m_channels]; |
45 (lrintf((maxProcessInputBlockSize + m_wlen) * ratio)); | 67 m_prevAdjustedPhase = new float *[m_channels]; |
46 | 68 if (m_sharpen) m_prevMag = new float *[m_channels]; |
47 std::cerr << "PhaseVocoderTimeStretcher: ratio = " << ratio | 69 else m_prevMag = 0; |
48 << ", n1 = " << m_n1 << ", n2 = " << m_n2 << ", wlen = " | 70 m_prevPercussiveCount = new int[m_channels]; |
49 << m_wlen << ", max = " << maxProcessInputBlockSize << ", outbuflen = " << m_outbuf->getSize() << std::endl; | 71 |
50 | 72 m_dbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); |
51 m_window = new Window<float>(HanningWindow, m_wlen), | |
52 | |
53 m_time = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * m_wlen); | 73 m_time = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * m_wlen); |
54 m_freq = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * m_wlen); | 74 m_freq = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * m_wlen); |
55 m_dbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); | 75 |
56 m_mashbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); | |
57 m_modulationbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); | |
58 m_prevPhase = (float *)fftwf_malloc(sizeof(float) * m_wlen); | |
59 m_prevAdjustedPhase = (float *)fftwf_malloc(sizeof(float) * m_wlen); | |
60 | |
61 m_plan = fftwf_plan_dft_1d(m_wlen, m_time, m_freq, FFTW_FORWARD, FFTW_ESTIMATE); | 76 m_plan = fftwf_plan_dft_1d(m_wlen, m_time, m_freq, FFTW_FORWARD, FFTW_ESTIMATE); |
62 m_iplan = fftwf_plan_dft_c2r_1d(m_wlen, m_freq, m_dbuf, FFTW_ESTIMATE); | 77 m_iplan = fftwf_plan_dft_c2r_1d(m_wlen, m_freq, m_dbuf, FFTW_ESTIMATE); |
63 | 78 |
79 m_inbuf = new RingBuffer<float> *[m_channels]; | |
80 m_outbuf = new RingBuffer<float> *[m_channels]; | |
81 m_mashbuf = new float *[m_channels]; | |
82 | |
83 m_modulationbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); | |
84 | |
85 for (size_t c = 0; c < m_channels; ++c) { | |
86 | |
87 m_prevPhase[c] = (float *)fftwf_malloc(sizeof(float) * m_wlen); | |
88 m_prevAdjustedPhase[c] = (float *)fftwf_malloc(sizeof(float) * m_wlen); | |
89 | |
90 if (m_sharpen) { | |
91 m_prevMag[c] = (float *)fftwf_malloc(sizeof(float) * m_wlen); | |
92 } | |
93 | |
94 m_inbuf[c] = new RingBuffer<float>(m_wlen); | |
95 m_outbuf[c] = new RingBuffer<float> | |
96 (lrintf((maxProcessInputBlockSize + m_wlen) * ratio)); | |
97 | |
98 m_mashbuf[c] = (float *)fftwf_malloc(sizeof(float) * m_wlen); | |
99 | |
100 for (int i = 0; i < m_wlen; ++i) { | |
101 m_mashbuf[c][i] = 0.0; | |
102 m_prevPhase[c][i] = 0.0; | |
103 m_prevAdjustedPhase[c][i] = 0.0; | |
104 if (m_sharpen) m_prevMag[c][i] = 0.0; | |
105 } | |
106 | |
107 m_prevPercussiveCount[c] = 0; | |
108 } | |
109 | |
64 for (int i = 0; i < m_wlen; ++i) { | 110 for (int i = 0; i < m_wlen; ++i) { |
65 m_mashbuf[i] = 0.0; | 111 m_modulationbuf[i] = 0.0; |
66 m_modulationbuf[i] = 0.0; | 112 } |
67 m_prevPhase[i] = 0.0; | 113 |
68 m_prevAdjustedPhase[i] = 0.0; | 114 std::cerr << "PhaseVocoderTimeStretcher: channels = " << channels |
69 } | 115 << ", ratio = " << ratio |
116 << ", n1 = " << m_n1 << ", n2 = " << m_n2 << ", wlen = " | |
117 << m_wlen << ", max = " << maxProcessInputBlockSize | |
118 << ", outbuflen = " << m_outbuf[0]->getSize() << std::endl; | |
70 } | 119 } |
71 | 120 |
72 PhaseVocoderTimeStretcher::~PhaseVocoderTimeStretcher() | 121 PhaseVocoderTimeStretcher::~PhaseVocoderTimeStretcher() |
73 { | 122 { |
74 std::cerr << "PhaseVocoderTimeStretcher::~PhaseVocoderTimeStretcher" << std::endl; | 123 std::cerr << "PhaseVocoderTimeStretcher::~PhaseVocoderTimeStretcher" << std::endl; |
77 fftwf_destroy_plan(m_iplan); | 126 fftwf_destroy_plan(m_iplan); |
78 | 127 |
79 fftwf_free(m_time); | 128 fftwf_free(m_time); |
80 fftwf_free(m_freq); | 129 fftwf_free(m_freq); |
81 fftwf_free(m_dbuf); | 130 fftwf_free(m_dbuf); |
82 fftwf_free(m_mashbuf); | 131 |
132 for (size_t c = 0; c < m_channels; ++c) { | |
133 | |
134 fftwf_free(m_mashbuf[c]); | |
135 fftwf_free(m_prevPhase[c]); | |
136 fftwf_free(m_prevAdjustedPhase[c]); | |
137 if (m_sharpen) fftwf_free(m_prevMag[c]); | |
138 | |
139 delete m_inbuf[c]; | |
140 delete m_outbuf[c]; | |
141 } | |
142 | |
83 fftwf_free(m_modulationbuf); | 143 fftwf_free(m_modulationbuf); |
84 fftwf_free(m_prevPhase); | 144 |
85 fftwf_free(m_prevAdjustedPhase); | 145 delete[] m_prevPhase; |
86 | 146 delete[] m_prevAdjustedPhase; |
87 delete m_inbuf; | 147 if (m_sharpen) delete[] m_prevMag; |
88 delete m_outbuf; | 148 delete[] m_prevPercussiveCount; |
149 delete[] m_inbuf; | |
150 delete[] m_outbuf; | |
151 delete[] m_mashbuf; | |
89 | 152 |
90 delete m_window; | 153 delete m_window; |
91 } | 154 } |
92 | 155 |
93 size_t | 156 size_t |
95 { | 158 { |
96 return getWindowSize() - getInputIncrement(); | 159 return getWindowSize() - getInputIncrement(); |
97 } | 160 } |
98 | 161 |
99 void | 162 void |
100 PhaseVocoderTimeStretcher::process(float *input, float *output, size_t samples) | 163 PhaseVocoderTimeStretcher::process(float **input, float **output, size_t samples) |
164 { | |
165 putInput(input, samples); | |
166 getOutput(output, lrintf(samples * m_ratio)); | |
167 } | |
168 | |
169 size_t | |
170 PhaseVocoderTimeStretcher::getRequiredInputSamples() const | |
171 { | |
172 if (m_inbuf[0]->getReadSpace() >= m_wlen) return 0; | |
173 return m_wlen - m_inbuf[0]->getReadSpace(); | |
174 } | |
175 | |
176 void | |
177 PhaseVocoderTimeStretcher::putInput(float **input, size_t samples) | |
101 { | 178 { |
102 // We need to add samples from input to our internal buffer. When | 179 // We need to add samples from input to our internal buffer. When |
103 // we have m_windowSize samples in the buffer, we can process it, | 180 // we have m_windowSize samples in the buffer, we can process it, |
104 // move the samples back by m_n1 and write the output onto our | 181 // move the samples back by m_n1 and write the output onto our |
105 // internal output buffer. If we have (samples * ratio) samples | 182 // internal output buffer. If we have (samples * ratio) samples |
113 | 190 |
114 // The processing latency is then m_wlen - m_n2. | 191 // The processing latency is then m_wlen - m_n2. |
115 | 192 |
116 size_t consumed = 0; | 193 size_t consumed = 0; |
117 | 194 |
118 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER | |
119 std::cerr << "PhaseVocoderTimeStretcher::process(" << samples << ", consumed = " << consumed << "), writable " << m_inbuf->getWriteSpace() <<", readable "<< m_outbuf->getReadSpace() << std::endl; | |
120 #endif | |
121 | |
122 while (consumed < samples) { | 195 while (consumed < samples) { |
123 | 196 |
124 size_t writable = m_inbuf->getWriteSpace(); | 197 size_t writable = m_inbuf[0]->getWriteSpace(); |
125 writable = std::min(writable, samples - consumed); | 198 writable = std::min(writable, samples - consumed); |
126 | 199 |
127 if (writable == 0) { | 200 if (writable == 0) { |
128 //!!! then what? I don't think this should happen, but | 201 //!!! then what? I don't think this should happen, but |
129 std::cerr << "WARNING: PhaseVocoderTimeStretcher::process: writable == 0" << std::endl; | 202 std::cerr << "WARNING: PhaseVocoderTimeStretcher::putInput: writable == 0" << std::endl; |
130 break; | 203 break; |
131 } | 204 } |
132 | 205 |
133 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER | 206 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER |
134 std::cerr << "writing " << writable << " from index " << consumed << " to inbuf, consumed will be " << consumed + writable << std::endl; | 207 std::cerr << "writing " << writable << " from index " << consumed << " to inbuf, consumed will be " << consumed + writable << std::endl; |
135 #endif | 208 #endif |
136 m_inbuf->write(input + consumed, writable); | 209 |
210 for (size_t c = 0; c < m_channels; ++c) { | |
211 m_inbuf[c]->write(input[c] + consumed, writable); | |
212 } | |
137 consumed += writable; | 213 consumed += writable; |
138 | 214 |
139 while (m_inbuf->getReadSpace() >= m_wlen && | 215 while (m_inbuf[0]->getReadSpace() >= m_wlen && |
140 m_outbuf->getWriteSpace() >= m_n2) { | 216 m_outbuf[0]->getWriteSpace() >= m_n2) { |
141 | 217 |
142 // We know we have at least m_wlen samples available | 218 // We know we have at least m_wlen samples available |
143 // in m_inbuf-> We need to peek m_wlen of them for | 219 // in m_inbuf. We need to peek m_wlen of them for |
144 // processing, and then read m_n1 to advance the read | 220 // processing, and then read m_n1 to advance the read |
145 // pointer. | 221 // pointer. |
146 | 222 |
147 size_t got = m_inbuf->peek(m_dbuf, m_wlen); | 223 size_t n2 = m_n2; |
148 assert(got == m_wlen); | 224 bool isPercussive = false; |
225 | |
226 for (size_t c = 0; c < m_channels; ++c) { | |
227 | |
228 size_t got = m_inbuf[c]->peek(m_dbuf, m_wlen); | |
229 assert(got == m_wlen); | |
149 | 230 |
150 processBlock(m_dbuf, m_mashbuf, m_modulationbuf); | 231 bool thisChannelPercussive = |
151 | 232 processBlock(c, m_dbuf, m_mashbuf[c], |
152 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER | 233 c == 0 ? m_modulationbuf : 0, |
153 std::cerr << "writing first " << m_n2 << " from mashbuf, skipping " << m_n1 << " on inbuf " << std::endl; | 234 isPercussive); |
154 #endif | 235 |
155 m_inbuf->skip(m_n1); | 236 if (thisChannelPercussive && c == 0) { |
156 | 237 isPercussive = true; |
157 for (size_t i = 0; i < m_n2; ++i) { | 238 } |
158 if (m_modulationbuf[i] > 0.f) { | 239 |
159 m_mashbuf[i] /= m_modulationbuf[i]; | 240 if (isPercussive) { |
241 n2 = m_n1; | |
242 } | |
243 | |
244 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER | |
245 std::cerr << "writing first " << m_n2 << " from mashbuf, skipping " << m_n1 << " on inbuf " << std::endl; | |
246 #endif | |
247 m_inbuf[c]->skip(m_n1); | |
248 | |
249 for (size_t i = 0; i < n2; ++i) { | |
250 if (m_modulationbuf[i] > 0.f) { | |
251 m_mashbuf[c][i] /= m_modulationbuf[i]; | |
252 } | |
253 } | |
254 | |
255 m_outbuf[c]->write(m_mashbuf[c], n2); | |
256 | |
257 for (size_t i = 0; i < m_wlen - n2; ++i) { | |
258 m_mashbuf[c][i] = m_mashbuf[c][i + n2]; | |
259 } | |
260 | |
261 for (size_t i = m_wlen - n2; i < m_wlen; ++i) { | |
262 m_mashbuf[c][i] = 0.0f; | |
160 } | 263 } |
161 } | 264 } |
162 | 265 |
163 m_outbuf->write(m_mashbuf, m_n2); | 266 for (size_t i = 0; i < m_wlen - n2; ++i) { |
164 | 267 m_modulationbuf[i] = m_modulationbuf[i + n2]; |
165 for (size_t i = 0; i < m_wlen - m_n2; ++i) { | |
166 m_mashbuf[i] = m_mashbuf[i + m_n2]; | |
167 m_modulationbuf[i] = m_modulationbuf[i + m_n2]; | |
168 } | 268 } |
169 | 269 |
170 for (size_t i = m_wlen - m_n2; i < m_wlen; ++i) { | 270 for (size_t i = m_wlen - n2; i < m_wlen; ++i) { |
171 m_mashbuf[i] = 0.0f; | |
172 m_modulationbuf[i] = 0.0f; | 271 m_modulationbuf[i] = 0.0f; |
173 } | 272 } |
174 } | 273 } |
175 | 274 |
176 // std::cerr << "WARNING: PhaseVocoderTimeStretcher::process: writespace not enough for output increment (" << m_outbuf->getWriteSpace() << " < " << m_n2 << ")" << std::endl; | 275 |
177 // } | 276 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER |
178 | 277 std::cerr << "loop ended: inbuf read space " << m_inbuf[0]->getReadSpace() << ", outbuf write space " << m_outbuf[0]->getWriteSpace() << std::endl; |
179 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER | 278 #endif |
180 std::cerr << "loop ended: inbuf read space " << m_inbuf->getReadSpace() << ", outbuf write space " << m_outbuf->getWriteSpace() << std::endl; | 279 } |
181 #endif | 280 |
182 } | 281 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER |
183 | 282 std::cerr << "PhaseVocoderTimeStretcher::putInput returning" << std::endl; |
184 size_t toRead = lrintf(samples * m_ratio); | 283 #endif |
185 | 284 } |
186 if (m_outbuf->getReadSpace() < toRead) { | 285 |
187 std::cerr << "WARNING: PhaseVocoderTimeStretcher::process: not enough data (yet?) (" << m_outbuf->getReadSpace() << " < " << toRead << ")" << std::endl; | 286 size_t |
188 size_t fill = toRead - m_outbuf->getReadSpace(); | 287 PhaseVocoderTimeStretcher::getAvailableOutputSamples() const |
189 for (size_t i = 0; i < fill; ++i) { | 288 { |
190 output[i] = 0.0; | 289 return m_outbuf[0]->getReadSpace(); |
191 } | 290 } |
192 m_outbuf->read(output + fill, m_outbuf->getReadSpace()); | 291 |
292 void | |
293 PhaseVocoderTimeStretcher::getOutput(float **output, size_t samples) | |
294 { | |
295 if (m_outbuf[0]->getReadSpace() < samples) { | |
296 std::cerr << "WARNING: PhaseVocoderTimeStretcher::getOutput: not enough data (yet?) (" << m_outbuf[0]->getReadSpace() << " < " << samples << ")" << std::endl; | |
297 size_t fill = samples - m_outbuf[0]->getReadSpace(); | |
298 for (size_t c = 0; c < m_channels; ++c) { | |
299 for (size_t i = 0; i < fill; ++i) { | |
300 output[c][i] = 0.0; | |
301 } | |
302 m_outbuf[c]->read(output[c] + fill, m_outbuf[c]->getReadSpace()); | |
303 } | |
193 } else { | 304 } else { |
194 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER | 305 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER |
195 std::cerr << "enough data - writing " << toRead << " from outbuf" << std::endl; | 306 std::cerr << "enough data - writing " << samples << " from outbuf" << std::endl; |
196 #endif | 307 #endif |
197 m_outbuf->read(output, toRead); | 308 for (size_t c = 0; c < m_channels; ++c) { |
198 } | 309 m_outbuf[c]->read(output[c], samples); |
199 | 310 } |
200 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER | 311 } |
201 std::cerr << "PhaseVocoderTimeStretcher::process returning" << std::endl; | 312 |
202 #endif | 313 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER |
203 } | 314 std::cerr << "PhaseVocoderTimeStretcher::getOutput returning" << std::endl; |
204 | 315 #endif |
205 void | 316 } |
206 PhaseVocoderTimeStretcher::processBlock(float *buf, float *out, float *modulation) | 317 |
318 bool | |
319 PhaseVocoderTimeStretcher::processBlock(size_t c, | |
320 float *buf, float *out, | |
321 float *modulation, | |
322 bool knownPercussive) | |
207 { | 323 { |
208 size_t i; | 324 size_t i; |
325 bool isPercussive = knownPercussive; | |
209 | 326 |
210 // buf contains m_wlen samples; out contains enough space for | 327 // buf contains m_wlen samples; out contains enough space for |
211 // m_wlen * ratio samples (we mix into out, rather than replacing) | 328 // m_wlen * ratio samples (we mix into out, rather than replacing) |
212 | 329 |
213 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER | 330 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER |
214 std::cerr << "PhaseVocoderTimeStretcher::processBlock" << std::endl; | 331 std::cerr << "PhaseVocoderTimeStretcher::processBlock (channel " << c << ")" << std::endl; |
215 #endif | 332 #endif |
216 | 333 |
217 m_window->cut(buf); | 334 m_window->cut(buf); |
218 | 335 |
219 for (i = 0; i < m_wlen/2; ++i) { | 336 for (i = 0; i < m_wlen/2; ++i) { |
227 m_time[i][1] = 0.0; | 344 m_time[i][1] = 0.0; |
228 } | 345 } |
229 | 346 |
230 fftwf_execute(m_plan); // m_time -> m_freq | 347 fftwf_execute(m_plan); // m_time -> m_freq |
231 | 348 |
349 if (m_sharpen && c == 0) { //!!! | |
350 | |
351 int count = 0; | |
352 | |
353 for (i = 0; i < m_wlen; ++i) { | |
354 | |
355 float mag = sqrtf(m_freq[i][0] * m_freq[i][0] + | |
356 m_freq[i][1] * m_freq[i][1]); | |
357 | |
358 if (m_prevMag[c][i] > 0) { | |
359 float magdiff = 20.f * log10f(mag / m_prevMag[c][i]); | |
360 if (magdiff > 3.f) ++count; | |
361 } | |
362 | |
363 m_prevMag[c][i] = mag; | |
364 } | |
365 | |
366 if (count > m_wlen / 6 && | |
367 count > m_prevPercussiveCount[c] * 1.2) { | |
368 isPercussive = true; | |
369 std::cerr << "isPercussive (count = " << count << ", prev = " << m_prevPercussiveCount[c] << ")" << std::endl; | |
370 } | |
371 | |
372 m_prevPercussiveCount[c] = count; | |
373 } | |
374 | |
375 size_t n2 = m_n2; | |
376 if (isPercussive) n2 = m_n1; | |
377 | |
232 for (i = 0; i < m_wlen; ++i) { | 378 for (i = 0; i < m_wlen; ++i) { |
233 | 379 |
234 float mag = sqrtf(m_freq[i][0] * m_freq[i][0] + | 380 float mag; |
235 m_freq[i][1] * m_freq[i][1]); | 381 |
382 if (m_sharpen && c == 0) { | |
383 mag = m_prevMag[c][i]; // can reuse this | |
384 } else { | |
385 mag = sqrtf(m_freq[i][0] * m_freq[i][0] + | |
386 m_freq[i][1] * m_freq[i][1]); | |
387 } | |
236 | 388 |
237 float phase = princargf(atan2f(m_freq[i][1], m_freq[i][0])); | 389 float phase = princargf(atan2f(m_freq[i][1], m_freq[i][0])); |
238 | 390 |
239 float omega = (2 * M_PI * m_n1 * i) / m_wlen; | 391 float omega = (2 * M_PI * m_n1 * i) / m_wlen; |
240 | 392 |
241 float expectedPhase = m_prevPhase[i] + omega; | 393 float expectedPhase = m_prevPhase[c][i] + omega; |
242 | 394 |
243 float phaseError = princargf(phase - expectedPhase); | 395 float phaseError = princargf(phase - expectedPhase); |
244 | 396 |
245 float phaseIncrement = (omega + phaseError) / m_n1; | 397 float phaseIncrement = (omega + phaseError) / m_n1; |
246 | 398 |
247 float adjustedPhase = m_prevAdjustedPhase[i] + m_n2 * phaseIncrement; | 399 float adjustedPhase = m_prevAdjustedPhase[c][i] + n2 * phaseIncrement; |
400 | |
401 if (isPercussive) adjustedPhase = phase; | |
248 | 402 |
249 float real = mag * cosf(adjustedPhase); | 403 float real = mag * cosf(adjustedPhase); |
250 float imag = mag * sinf(adjustedPhase); | 404 float imag = mag * sinf(adjustedPhase); |
251 m_freq[i][0] = real; | 405 m_freq[i][0] = real; |
252 m_freq[i][1] = imag; | 406 m_freq[i][1] = imag; |
253 | 407 |
254 m_prevPhase[i] = phase; | 408 m_prevPhase[c][i] = phase; |
255 m_prevAdjustedPhase[i] = adjustedPhase; | 409 m_prevAdjustedPhase[c][i] = adjustedPhase; |
256 } | 410 } |
257 | 411 |
258 fftwf_execute(m_iplan); // m_freq -> in, inverse fft | 412 fftwf_execute(m_iplan); // m_freq -> in, inverse fft |
259 | 413 |
260 for (i = 0; i < m_wlen/2; ++i) { | 414 for (i = 0; i < m_wlen/2; ++i) { |
262 buf[i] = buf[i + m_wlen/2] / m_wlen; | 416 buf[i] = buf[i + m_wlen/2] / m_wlen; |
263 buf[i + m_wlen/2] = temp; | 417 buf[i + m_wlen/2] = temp; |
264 } | 418 } |
265 | 419 |
266 m_window->cut(buf); | 420 m_window->cut(buf); |
267 /* | 421 |
268 int div = m_wlen / m_n2; | |
269 if (div > 1) div /= 2; | |
270 for (i = 0; i < m_wlen; ++i) { | 422 for (i = 0; i < m_wlen; ++i) { |
271 buf[i] /= div; | 423 out[i] += buf[i]; |
272 } | 424 } |
273 */ | 425 |
274 | 426 if (modulation) { |
275 float area = m_window->getArea(); | 427 |
276 | 428 float area = m_window->getArea(); |
277 for (i = 0; i < m_wlen; ++i) { | 429 |
278 out[i] += buf[i]; | 430 for (i = 0; i < m_wlen; ++i) { |
279 float val = m_window->getValue(i); | 431 float val = m_window->getValue(i); |
280 modulation[i] += val * area; | 432 modulation[i] += val * area; |
281 } | 433 } |
282 } | 434 } |
283 | 435 |
436 return isPercussive; | |
437 } | |
438 |