# HG changeset patch # User Chris Cannam # Date 1158088392 0 # Node ID 00ed645f41758e606e01e09795a21d6038e98ee7 # Parent ee967635c728ba1eae3f2fcde713a7150deade40 * various fixes in the time stretcher diff -r ee967635c728 -r 00ed645f4175 audioio/AudioCallbackPlaySource.cpp --- a/audioio/AudioCallbackPlaySource.cpp Tue Sep 12 16:43:00 2006 +0000 +++ b/audioio/AudioCallbackPlaySource.cpp Tue Sep 12 19:13:12 2006 +0000 @@ -597,11 +597,13 @@ // std::cerr << "TimeStretcherData::TimeStretcherData(" << channels << ", " << factor << ", " << blockSize << ")" << std::endl; for (size_t ch = 0; ch < channels; ++ch) { + m_stretcher[ch] = StretcherBuffer - //!!! We really need to measure performance and work out - //what sort of quality level to use -- or at least to - //allow the user to configure it - (new IntegerTimeStretcher(factor, blockSize, 1024), +//!!! + (new IntegerTimeStretcher(factor, + blockSize, +// 128), + (blockSize/2) / factor), new float[lrintf(blockSize * factor)]); } m_stretchInputBuffer = new float[blockSize]; @@ -660,7 +662,10 @@ if (factor != 1) { TimeStretcherData *newStretcher = new TimeStretcherData (getTargetChannelCount(), factor, - factor > 1 ? getTargetBlockSize() : getTargetBlockSize() / factor); +// factor > 1 ? getTargetBlockSize() : getTargetBlockSize() / factor); + //!!! doesn't work if the block size > getTargetBlockSize(), but it + // should be made to + getTargetBlockSize()); m_slowdownCounter = 0; m_timeStretcher = newStretcher; } else { diff -r ee967635c728 -r 00ed645f4175 audioio/IntegerTimeStretcher.cpp --- a/audioio/IntegerTimeStretcher.cpp Tue Sep 12 16:43:00 2006 +0000 +++ b/audioio/IntegerTimeStretcher.cpp Tue Sep 12 19:13:12 2006 +0000 @@ -38,6 +38,7 @@ m_freq = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * m_wlen); m_dbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); m_mashbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); + m_modulationbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); m_prevPhase = (float *)fftwf_malloc(sizeof(float) * m_wlen); m_prevAdjustedPhase = (float *)fftwf_malloc(sizeof(float) * m_wlen); @@ -46,6 +47,7 @@ for (int i = 0; i < m_wlen; ++i) { m_mashbuf[i] = 0.0; + m_modulationbuf[i] = 0.0; m_prevPhase[i] = 0.0; m_prevAdjustedPhase[i] = 0.0; } @@ -62,6 +64,7 @@ fftwf_free(m_freq); fftwf_free(m_dbuf); fftwf_free(m_mashbuf); + fftwf_free(m_modulationbuf); fftwf_free(m_prevPhase); fftwf_free(m_prevAdjustedPhase); @@ -125,19 +128,29 @@ size_t got = m_inbuf.peek(m_dbuf, m_wlen); assert(got == m_wlen); - processBlock(m_dbuf, m_mashbuf); + processBlock(m_dbuf, m_mashbuf, m_modulationbuf); #ifdef DEBUG_INTEGER_TIME_STRETCHER std::cerr << "writing first " << m_n2 << " from mashbuf, skipping " << m_n1 << " on inbuf " << std::endl; #endif m_inbuf.skip(m_n1); + + for (size_t i = 0; i < m_n2; ++i) { + if (m_modulationbuf[i] > 0.f) { + m_mashbuf[i] /= m_modulationbuf[i]; + } + } + m_outbuf.write(m_mashbuf, m_n2); for (size_t i = 0; i < m_wlen - m_n2; ++i) { m_mashbuf[i] = m_mashbuf[i + m_n2]; + m_modulationbuf[i] = m_modulationbuf[i + m_n2]; } + for (size_t i = m_wlen - m_n2; i < m_wlen; ++i) { m_mashbuf[i] = 0.0f; + m_modulationbuf[i] = 0.0f; } } @@ -171,7 +184,7 @@ } void -IntegerTimeStretcher::processBlock(float *buf, float *out) +IntegerTimeStretcher::processBlock(float *buf, float *out, float *modulation) { size_t i; @@ -232,14 +245,15 @@ } m_window->cut(buf); - +/* int div = m_wlen / m_n2; if (div > 1) div /= 2; for (i = 0; i < m_wlen; ++i) { buf[i] /= div; } - +*/ for (i = 0; i < m_wlen; ++i) { out[i] += buf[i]; + modulation[i] += m_window->getValue(i); } } diff -r ee967635c728 -r 00ed645f4175 audioio/IntegerTimeStretcher.h --- a/audioio/IntegerTimeStretcher.h Tue Sep 12 16:43:00 2006 +0000 +++ b/audioio/IntegerTimeStretcher.h Tue Sep 12 19:13:12 2006 +0000 @@ -72,7 +72,20 @@ size_t getProcessingLatency() const; protected: - void processBlock(float *in, float *out); + /** + * Process a single phase vocoder frame. + * + * Take m_wlen time-domain source samples from in, perform an FFT, + * phase shift, and IFFT, and add the results to out (presumably + * overlapping parts of existing data from prior frames). + * + * Also add to the modulation output the results of windowing a + * set of 1s with the resynthesis window -- this can then be used + * to ensure the output has the correct magnitude in cases where + * the window overlap varies or otherwise results in something + * other than a flat sum. + */ + void processBlock(float *in, float *out, float *modulation); float m_ratio; size_t m_n1; @@ -92,6 +105,7 @@ RingBuffer m_inbuf; RingBuffer m_outbuf; float *m_mashbuf; + float *m_modulationbuf; }; #endif