changeset 13:00ed645f4175

* various fixes in the time stretcher
author Chris Cannam
date Tue, 12 Sep 2006 19:13:12 +0000
parents ee967635c728
children 085f34c73939
files audioio/AudioCallbackPlaySource.cpp audioio/IntegerTimeStretcher.cpp audioio/IntegerTimeStretcher.h
diffstat 3 files changed, 43 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- 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 {
--- 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);
     }
 }
--- 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<float> m_inbuf;
     RingBuffer<float> m_outbuf;
     float *m_mashbuf;
+    float *m_modulationbuf;
 };
 
 #endif