diff 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
line wrap: on
line diff
--- a/audioio/IntegerTimeStretcher.cpp	Tue Sep 12 12:15:44 2006 +0000
+++ b/audioio/IntegerTimeStretcher.cpp	Tue Sep 12 16:43:00 2006 +0000
@@ -20,30 +20,34 @@
 
 //#define DEBUG_INTEGER_TIME_STRETCHER 1
 
-IntegerTimeStretcher::IntegerTimeStretcher(size_t ratio,
+IntegerTimeStretcher::IntegerTimeStretcher(float ratio,
 					   size_t maxProcessInputBlockSize,
 					   size_t inputIncrement,
 					   size_t windowSize,
 					   WindowType windowType) :
     m_ratio(ratio),
     m_n1(inputIncrement),
-    m_n2(m_n1 * ratio),
+    m_n2(lrintf(m_n1 * ratio)),
     m_wlen(std::max(windowSize, m_n2 * 2)),
     m_inbuf(m_wlen),
-    m_outbuf(maxProcessInputBlockSize * ratio)
+    m_outbuf(maxProcessInputBlockSize * ratio + 1024) //!!!
 {
     m_window = new Window<float>(windowType, m_wlen),
 
     m_time = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * m_wlen);
     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_prevPhase = (float *)fftwf_malloc(sizeof(float) * m_wlen);
+    m_prevAdjustedPhase = (float *)fftwf_malloc(sizeof(float) * m_wlen);
 
     m_plan = fftwf_plan_dft_1d(m_wlen, m_time, m_freq, FFTW_FORWARD, FFTW_ESTIMATE);
     m_iplan = fftwf_plan_dft_c2r_1d(m_wlen, m_freq, m_dbuf, FFTW_ESTIMATE);
 
-    m_mashbuf = new float[m_wlen];
     for (int i = 0; i < m_wlen; ++i) {
 	m_mashbuf[i] = 0.0;
+        m_prevPhase[i] = 0.0;
+        m_prevAdjustedPhase[i] = 0.0;
     }
 }
 
@@ -57,9 +61,11 @@
     fftwf_free(m_time);
     fftwf_free(m_freq);
     fftwf_free(m_dbuf);
+    fftwf_free(m_mashbuf);
+    fftwf_free(m_prevPhase);
+    fftwf_free(m_prevAdjustedPhase);
 
     delete m_window;
-    delete m_mashbuf;
 }	
 
 size_t
@@ -143,18 +149,20 @@
 #endif
     }
 
-    if (m_outbuf.getReadSpace() < samples * m_ratio) {
-	std::cerr << "WARNING: IntegerTimeStretcher::process: not enough data (yet?) (" << m_outbuf.getReadSpace() << " < " << (samples * m_ratio) << ")" << std::endl;
-	size_t fill = samples * m_ratio - m_outbuf.getReadSpace();
+    size_t toRead = lrintf(samples * m_ratio);
+
+    if (m_outbuf.getReadSpace() < toRead) {
+	std::cerr << "WARNING: IntegerTimeStretcher::process: not enough data (yet?) (" << m_outbuf.getReadSpace() << " < " << toRead << ")" << std::endl;
+	size_t fill = toRead - m_outbuf.getReadSpace();
 	for (size_t i = 0; i < fill; ++i) {
 	    output[i] = 0.0;
 	}
 	m_outbuf.read(output + fill, m_outbuf.getReadSpace());
     } else {
 #ifdef DEBUG_INTEGER_TIME_STRETCHER
-	std::cerr << "enough data - writing " << samples * m_ratio << " from outbuf" << std::endl;
+	std::cerr << "enough data - writing " << toRead << " from outbuf" << std::endl;
 #endif
-	m_outbuf.read(output, samples * m_ratio);
+	m_outbuf.read(output, toRead);
     }
 
 #ifdef DEBUG_INTEGER_TIME_STRETCHER
@@ -194,14 +202,25 @@
 	float mag = sqrtf(m_freq[i][0] * m_freq[i][0] +
 			  m_freq[i][1] * m_freq[i][1]);
 		
-	float phase = atan2f(m_freq[i][1], m_freq[i][0]);
+        float phase = princargf(atan2f(m_freq[i][1], m_freq[i][0]));
+
+        float omega = (2 * M_PI * m_n1 * i) / m_wlen;
 	
-	phase = phase * m_ratio;
+        float expectedPhase = m_prevPhase[i] + omega;
+
+        float phaseError = princargf(phase - expectedPhase);
+
+        float phaseIncrement = (omega + phaseError) / m_n1;
+
+        float adjustedPhase = m_prevAdjustedPhase[i] + m_n2 * phaseIncrement;
 	
-	float real = mag * cosf(phase);
-	float imag = mag * sinf(phase);
+	float real = mag * cosf(adjustedPhase);
+	float imag = mag * sinf(adjustedPhase);
 	m_freq[i][0] = real;
 	m_freq[i][1] = imag;
+
+        m_prevPhase[i] = phase;
+        m_prevAdjustedPhase[i] = adjustedPhase;
     }
     
     fftwf_execute(m_iplan); // m_freq -> in, inverse fft