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