Mercurial > hg > sonic-visualiser
comparison audioio/IntegerTimeStretcher.cpp @ 12:ee967635c728
* Some work on making the time stretcher squash as well as stretch
author | Chris Cannam |
---|---|
date | Tue, 12 Sep 2006 16:43:00 +0000 |
parents | cd5d7ff8ef38 |
children | 00ed645f4175 |
comparison
equal
deleted
inserted
replaced
11:0dbd08e365ce | 12:ee967635c728 |
---|---|
18 #include <iostream> | 18 #include <iostream> |
19 #include <cassert> | 19 #include <cassert> |
20 | 20 |
21 //#define DEBUG_INTEGER_TIME_STRETCHER 1 | 21 //#define DEBUG_INTEGER_TIME_STRETCHER 1 |
22 | 22 |
23 IntegerTimeStretcher::IntegerTimeStretcher(size_t ratio, | 23 IntegerTimeStretcher::IntegerTimeStretcher(float ratio, |
24 size_t maxProcessInputBlockSize, | 24 size_t maxProcessInputBlockSize, |
25 size_t inputIncrement, | 25 size_t inputIncrement, |
26 size_t windowSize, | 26 size_t windowSize, |
27 WindowType windowType) : | 27 WindowType windowType) : |
28 m_ratio(ratio), | 28 m_ratio(ratio), |
29 m_n1(inputIncrement), | 29 m_n1(inputIncrement), |
30 m_n2(m_n1 * ratio), | 30 m_n2(lrintf(m_n1 * ratio)), |
31 m_wlen(std::max(windowSize, m_n2 * 2)), | 31 m_wlen(std::max(windowSize, m_n2 * 2)), |
32 m_inbuf(m_wlen), | 32 m_inbuf(m_wlen), |
33 m_outbuf(maxProcessInputBlockSize * ratio) | 33 m_outbuf(maxProcessInputBlockSize * ratio + 1024) //!!! |
34 { | 34 { |
35 m_window = new Window<float>(windowType, m_wlen), | 35 m_window = new Window<float>(windowType, m_wlen), |
36 | 36 |
37 m_time = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * m_wlen); | 37 m_time = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * m_wlen); |
38 m_freq = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * m_wlen); | 38 m_freq = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * m_wlen); |
39 m_dbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); | 39 m_dbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); |
40 m_mashbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); | |
41 m_prevPhase = (float *)fftwf_malloc(sizeof(float) * m_wlen); | |
42 m_prevAdjustedPhase = (float *)fftwf_malloc(sizeof(float) * m_wlen); | |
40 | 43 |
41 m_plan = fftwf_plan_dft_1d(m_wlen, m_time, m_freq, FFTW_FORWARD, FFTW_ESTIMATE); | 44 m_plan = fftwf_plan_dft_1d(m_wlen, m_time, m_freq, FFTW_FORWARD, FFTW_ESTIMATE); |
42 m_iplan = fftwf_plan_dft_c2r_1d(m_wlen, m_freq, m_dbuf, FFTW_ESTIMATE); | 45 m_iplan = fftwf_plan_dft_c2r_1d(m_wlen, m_freq, m_dbuf, FFTW_ESTIMATE); |
43 | 46 |
44 m_mashbuf = new float[m_wlen]; | |
45 for (int i = 0; i < m_wlen; ++i) { | 47 for (int i = 0; i < m_wlen; ++i) { |
46 m_mashbuf[i] = 0.0; | 48 m_mashbuf[i] = 0.0; |
49 m_prevPhase[i] = 0.0; | |
50 m_prevAdjustedPhase[i] = 0.0; | |
47 } | 51 } |
48 } | 52 } |
49 | 53 |
50 IntegerTimeStretcher::~IntegerTimeStretcher() | 54 IntegerTimeStretcher::~IntegerTimeStretcher() |
51 { | 55 { |
55 fftwf_destroy_plan(m_iplan); | 59 fftwf_destroy_plan(m_iplan); |
56 | 60 |
57 fftwf_free(m_time); | 61 fftwf_free(m_time); |
58 fftwf_free(m_freq); | 62 fftwf_free(m_freq); |
59 fftwf_free(m_dbuf); | 63 fftwf_free(m_dbuf); |
64 fftwf_free(m_mashbuf); | |
65 fftwf_free(m_prevPhase); | |
66 fftwf_free(m_prevAdjustedPhase); | |
60 | 67 |
61 delete m_window; | 68 delete m_window; |
62 delete m_mashbuf; | |
63 } | 69 } |
64 | 70 |
65 size_t | 71 size_t |
66 IntegerTimeStretcher::getProcessingLatency() const | 72 IntegerTimeStretcher::getProcessingLatency() const |
67 { | 73 { |
141 #ifdef DEBUG_INTEGER_TIME_STRETCHER | 147 #ifdef DEBUG_INTEGER_TIME_STRETCHER |
142 std::cerr << "loop ended: inbuf read space " << m_inbuf.getReadSpace() << ", outbuf write space " << m_outbuf.getWriteSpace() << std::endl; | 148 std::cerr << "loop ended: inbuf read space " << m_inbuf.getReadSpace() << ", outbuf write space " << m_outbuf.getWriteSpace() << std::endl; |
143 #endif | 149 #endif |
144 } | 150 } |
145 | 151 |
146 if (m_outbuf.getReadSpace() < samples * m_ratio) { | 152 size_t toRead = lrintf(samples * m_ratio); |
147 std::cerr << "WARNING: IntegerTimeStretcher::process: not enough data (yet?) (" << m_outbuf.getReadSpace() << " < " << (samples * m_ratio) << ")" << std::endl; | 153 |
148 size_t fill = samples * m_ratio - m_outbuf.getReadSpace(); | 154 if (m_outbuf.getReadSpace() < toRead) { |
155 std::cerr << "WARNING: IntegerTimeStretcher::process: not enough data (yet?) (" << m_outbuf.getReadSpace() << " < " << toRead << ")" << std::endl; | |
156 size_t fill = toRead - m_outbuf.getReadSpace(); | |
149 for (size_t i = 0; i < fill; ++i) { | 157 for (size_t i = 0; i < fill; ++i) { |
150 output[i] = 0.0; | 158 output[i] = 0.0; |
151 } | 159 } |
152 m_outbuf.read(output + fill, m_outbuf.getReadSpace()); | 160 m_outbuf.read(output + fill, m_outbuf.getReadSpace()); |
153 } else { | 161 } else { |
154 #ifdef DEBUG_INTEGER_TIME_STRETCHER | 162 #ifdef DEBUG_INTEGER_TIME_STRETCHER |
155 std::cerr << "enough data - writing " << samples * m_ratio << " from outbuf" << std::endl; | 163 std::cerr << "enough data - writing " << toRead << " from outbuf" << std::endl; |
156 #endif | 164 #endif |
157 m_outbuf.read(output, samples * m_ratio); | 165 m_outbuf.read(output, toRead); |
158 } | 166 } |
159 | 167 |
160 #ifdef DEBUG_INTEGER_TIME_STRETCHER | 168 #ifdef DEBUG_INTEGER_TIME_STRETCHER |
161 std::cerr << "IntegerTimeStretcher::process returning" << std::endl; | 169 std::cerr << "IntegerTimeStretcher::process returning" << std::endl; |
162 #endif | 170 #endif |
192 for (i = 0; i < m_wlen; ++i) { | 200 for (i = 0; i < m_wlen; ++i) { |
193 | 201 |
194 float mag = sqrtf(m_freq[i][0] * m_freq[i][0] + | 202 float mag = sqrtf(m_freq[i][0] * m_freq[i][0] + |
195 m_freq[i][1] * m_freq[i][1]); | 203 m_freq[i][1] * m_freq[i][1]); |
196 | 204 |
197 float phase = atan2f(m_freq[i][1], m_freq[i][0]); | 205 float phase = princargf(atan2f(m_freq[i][1], m_freq[i][0])); |
206 | |
207 float omega = (2 * M_PI * m_n1 * i) / m_wlen; | |
198 | 208 |
199 phase = phase * m_ratio; | 209 float expectedPhase = m_prevPhase[i] + omega; |
210 | |
211 float phaseError = princargf(phase - expectedPhase); | |
212 | |
213 float phaseIncrement = (omega + phaseError) / m_n1; | |
214 | |
215 float adjustedPhase = m_prevAdjustedPhase[i] + m_n2 * phaseIncrement; | |
200 | 216 |
201 float real = mag * cosf(phase); | 217 float real = mag * cosf(adjustedPhase); |
202 float imag = mag * sinf(phase); | 218 float imag = mag * sinf(adjustedPhase); |
203 m_freq[i][0] = real; | 219 m_freq[i][0] = real; |
204 m_freq[i][1] = imag; | 220 m_freq[i][1] = imag; |
221 | |
222 m_prevPhase[i] = phase; | |
223 m_prevAdjustedPhase[i] = adjustedPhase; | |
205 } | 224 } |
206 | 225 |
207 fftwf_execute(m_iplan); // m_freq -> in, inverse fft | 226 fftwf_execute(m_iplan); // m_freq -> in, inverse fft |
208 | 227 |
209 for (i = 0; i < m_wlen/2; ++i) { | 228 for (i = 0; i < m_wlen/2; ++i) { |