Mercurial > hg > sonic-visualiser
comparison audioio/PhaseVocoderTimeStretcher.cpp @ 15:cc566264c935
* timestretcher improvements -- simplify API (it can calculate its own
processing block sizes etc)
author | Chris Cannam |
---|---|
date | Wed, 13 Sep 2006 11:56:44 +0000 |
parents | 085f34c73939 |
children | 3715efc38f95 |
comparison
equal
deleted
inserted
replaced
14:085f34c73939 | 15:cc566264c935 |
---|---|
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(float ratio, |
24 size_t maxProcessInputBlockSize, | 24 size_t maxProcessInputBlockSize) : |
25 size_t inputIncrement, | 25 m_ratio(ratio) |
26 size_t windowSize, | 26 //, |
27 WindowType windowType) : | 27 // m_n1(inputIncrement), |
28 m_ratio(ratio), | 28 // m_n2(lrintf(m_n1 * ratio)), |
29 m_n1(inputIncrement), | 29 // m_wlen(std::max(windowSize, m_n2 * 2)), |
30 m_n2(lrintf(m_n1 * ratio)), | 30 // m_inbuf(m_wlen), |
31 m_wlen(std::max(windowSize, m_n2 * 2)), | 31 // m_outbuf(maxProcessInputBlockSize * ratio + 1024) //!!! |
32 m_inbuf(m_wlen), | 32 { |
33 m_outbuf(maxProcessInputBlockSize * ratio + 1024) //!!! | 33 if (ratio < 1) { |
34 { | 34 m_n1 = 512; |
35 m_window = new Window<float>(windowType, m_wlen), | 35 m_n2 = m_n1 * ratio; |
36 m_wlen = 1024; | |
37 } else { | |
38 m_n2 = 512; | |
39 m_n1 = m_n2 / ratio; | |
40 m_wlen = 1024; | |
41 } | |
42 | |
43 m_inbuf = new RingBuffer<float>(m_wlen); | |
44 m_outbuf = new RingBuffer<float> | |
45 (lrintf((maxProcessInputBlockSize + m_wlen) * ratio)); | |
46 | |
47 std::cerr << "PhaseVocoderTimeStretcher: ratio = " << ratio | |
48 << ", n1 = " << m_n1 << ", n2 = " << m_n2 << ", wlen = " | |
49 << m_wlen << ", max = " << maxProcessInputBlockSize << ", outbuflen = " << m_outbuf->getSize() << std::endl; | |
50 | |
51 m_window = new Window<float>(HanningWindow, m_wlen), | |
36 | 52 |
37 m_time = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * m_wlen); | 53 m_time = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * m_wlen); |
38 m_freq = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * m_wlen); | 54 m_freq = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * m_wlen); |
39 m_dbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); | 55 m_dbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); |
40 m_mashbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); | 56 m_mashbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); |
66 fftwf_free(m_mashbuf); | 82 fftwf_free(m_mashbuf); |
67 fftwf_free(m_modulationbuf); | 83 fftwf_free(m_modulationbuf); |
68 fftwf_free(m_prevPhase); | 84 fftwf_free(m_prevPhase); |
69 fftwf_free(m_prevAdjustedPhase); | 85 fftwf_free(m_prevAdjustedPhase); |
70 | 86 |
87 delete m_inbuf; | |
88 delete m_outbuf; | |
89 | |
71 delete m_window; | 90 delete m_window; |
72 } | 91 } |
73 | 92 |
74 size_t | 93 size_t |
75 PhaseVocoderTimeStretcher::getProcessingLatency() const | 94 PhaseVocoderTimeStretcher::getProcessingLatency() const |
95 // The processing latency is then m_wlen - m_n2. | 114 // The processing latency is then m_wlen - m_n2. |
96 | 115 |
97 size_t consumed = 0; | 116 size_t consumed = 0; |
98 | 117 |
99 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER | 118 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER |
100 std::cerr << "PhaseVocoderTimeStretcher::process(" << samples << ", consumed = " << consumed << "), writable " << m_inbuf.getWriteSpace() <<", readable "<< m_outbuf.getReadSpace() << std::endl; | 119 std::cerr << "PhaseVocoderTimeStretcher::process(" << samples << ", consumed = " << consumed << "), writable " << m_inbuf->getWriteSpace() <<", readable "<< m_outbuf->getReadSpace() << std::endl; |
101 #endif | 120 #endif |
102 | 121 |
103 while (consumed < samples) { | 122 while (consumed < samples) { |
104 | 123 |
105 size_t writable = m_inbuf.getWriteSpace(); | 124 size_t writable = m_inbuf->getWriteSpace(); |
106 writable = std::min(writable, samples - consumed); | 125 writable = std::min(writable, samples - consumed); |
107 | 126 |
108 if (writable == 0) { | 127 if (writable == 0) { |
109 //!!! then what? I don't think this should happen, but | 128 //!!! then what? I don't think this should happen, but |
110 std::cerr << "WARNING: PhaseVocoderTimeStretcher::process: writable == 0" << std::endl; | 129 std::cerr << "WARNING: PhaseVocoderTimeStretcher::process: writable == 0" << std::endl; |
112 } | 131 } |
113 | 132 |
114 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER | 133 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER |
115 std::cerr << "writing " << writable << " from index " << consumed << " to inbuf, consumed will be " << consumed + writable << std::endl; | 134 std::cerr << "writing " << writable << " from index " << consumed << " to inbuf, consumed will be " << consumed + writable << std::endl; |
116 #endif | 135 #endif |
117 m_inbuf.write(input + consumed, writable); | 136 m_inbuf->write(input + consumed, writable); |
118 consumed += writable; | 137 consumed += writable; |
119 | 138 |
120 while (m_inbuf.getReadSpace() >= m_wlen && | 139 while (m_inbuf->getReadSpace() >= m_wlen && |
121 m_outbuf.getWriteSpace() >= m_n2) { | 140 m_outbuf->getWriteSpace() >= m_n2) { |
122 | 141 |
123 // We know we have at least m_wlen samples available | 142 // We know we have at least m_wlen samples available |
124 // in m_inbuf. We need to peek m_wlen of them for | 143 // in m_inbuf-> We need to peek m_wlen of them for |
125 // processing, and then read m_n1 to advance the read | 144 // processing, and then read m_n1 to advance the read |
126 // pointer. | 145 // pointer. |
127 | 146 |
128 size_t got = m_inbuf.peek(m_dbuf, m_wlen); | 147 size_t got = m_inbuf->peek(m_dbuf, m_wlen); |
129 assert(got == m_wlen); | 148 assert(got == m_wlen); |
130 | 149 |
131 processBlock(m_dbuf, m_mashbuf, m_modulationbuf); | 150 processBlock(m_dbuf, m_mashbuf, m_modulationbuf); |
132 | 151 |
133 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER | 152 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER |
134 std::cerr << "writing first " << m_n2 << " from mashbuf, skipping " << m_n1 << " on inbuf " << std::endl; | 153 std::cerr << "writing first " << m_n2 << " from mashbuf, skipping " << m_n1 << " on inbuf " << std::endl; |
135 #endif | 154 #endif |
136 m_inbuf.skip(m_n1); | 155 m_inbuf->skip(m_n1); |
137 | 156 |
138 for (size_t i = 0; i < m_n2; ++i) { | 157 for (size_t i = 0; i < m_n2; ++i) { |
139 if (m_modulationbuf[i] > 0.f) { | 158 if (m_modulationbuf[i] > 0.f) { |
140 m_mashbuf[i] /= m_modulationbuf[i]; | 159 m_mashbuf[i] /= m_modulationbuf[i]; |
141 } | 160 } |
142 } | 161 } |
143 | 162 |
144 m_outbuf.write(m_mashbuf, m_n2); | 163 m_outbuf->write(m_mashbuf, m_n2); |
145 | 164 |
146 for (size_t i = 0; i < m_wlen - m_n2; ++i) { | 165 for (size_t i = 0; i < m_wlen - m_n2; ++i) { |
147 m_mashbuf[i] = m_mashbuf[i + m_n2]; | 166 m_mashbuf[i] = m_mashbuf[i + m_n2]; |
148 m_modulationbuf[i] = m_modulationbuf[i + m_n2]; | 167 m_modulationbuf[i] = m_modulationbuf[i + m_n2]; |
149 } | 168 } |
152 m_mashbuf[i] = 0.0f; | 171 m_mashbuf[i] = 0.0f; |
153 m_modulationbuf[i] = 0.0f; | 172 m_modulationbuf[i] = 0.0f; |
154 } | 173 } |
155 } | 174 } |
156 | 175 |
157 // std::cerr << "WARNING: PhaseVocoderTimeStretcher::process: writespace not enough for output increment (" << m_outbuf.getWriteSpace() << " < " << m_n2 << ")" << std::endl; | 176 // std::cerr << "WARNING: PhaseVocoderTimeStretcher::process: writespace not enough for output increment (" << m_outbuf->getWriteSpace() << " < " << m_n2 << ")" << std::endl; |
158 // } | 177 // } |
159 | 178 |
160 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER | 179 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER |
161 std::cerr << "loop ended: inbuf read space " << m_inbuf.getReadSpace() << ", outbuf write space " << m_outbuf.getWriteSpace() << std::endl; | 180 std::cerr << "loop ended: inbuf read space " << m_inbuf->getReadSpace() << ", outbuf write space " << m_outbuf->getWriteSpace() << std::endl; |
162 #endif | 181 #endif |
163 } | 182 } |
164 | 183 |
165 size_t toRead = lrintf(samples * m_ratio); | 184 size_t toRead = lrintf(samples * m_ratio); |
166 | 185 |
167 if (m_outbuf.getReadSpace() < toRead) { | 186 if (m_outbuf->getReadSpace() < toRead) { |
168 std::cerr << "WARNING: PhaseVocoderTimeStretcher::process: not enough data (yet?) (" << m_outbuf.getReadSpace() << " < " << toRead << ")" << std::endl; | 187 std::cerr << "WARNING: PhaseVocoderTimeStretcher::process: not enough data (yet?) (" << m_outbuf->getReadSpace() << " < " << toRead << ")" << std::endl; |
169 size_t fill = toRead - m_outbuf.getReadSpace(); | 188 size_t fill = toRead - m_outbuf->getReadSpace(); |
170 for (size_t i = 0; i < fill; ++i) { | 189 for (size_t i = 0; i < fill; ++i) { |
171 output[i] = 0.0; | 190 output[i] = 0.0; |
172 } | 191 } |
173 m_outbuf.read(output + fill, m_outbuf.getReadSpace()); | 192 m_outbuf->read(output + fill, m_outbuf->getReadSpace()); |
174 } else { | 193 } else { |
175 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER | 194 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER |
176 std::cerr << "enough data - writing " << toRead << " from outbuf" << std::endl; | 195 std::cerr << "enough data - writing " << toRead << " from outbuf" << std::endl; |
177 #endif | 196 #endif |
178 m_outbuf.read(output, toRead); | 197 m_outbuf->read(output, toRead); |
179 } | 198 } |
180 | 199 |
181 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER | 200 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER |
182 std::cerr << "PhaseVocoderTimeStretcher::process returning" << std::endl; | 201 std::cerr << "PhaseVocoderTimeStretcher::process returning" << std::endl; |
183 #endif | 202 #endif |
250 if (div > 1) div /= 2; | 269 if (div > 1) div /= 2; |
251 for (i = 0; i < m_wlen; ++i) { | 270 for (i = 0; i < m_wlen; ++i) { |
252 buf[i] /= div; | 271 buf[i] /= div; |
253 } | 272 } |
254 */ | 273 */ |
274 | |
275 float area = m_window->getArea(); | |
276 | |
255 for (i = 0; i < m_wlen; ++i) { | 277 for (i = 0; i < m_wlen; ++i) { |
256 out[i] += buf[i]; | 278 out[i] += buf[i]; |
257 modulation[i] += m_window->getValue(i); | 279 float val = m_window->getValue(i); |
258 } | 280 modulation[i] += val * area; |
259 } | 281 } |
282 } | |
283 |