changeset 22:80126455d169

* add samplerate parameter to timestretcher (not properly used yet), and update credits
author Chris Cannam
date Fri, 15 Sep 2006 13:35:37 +0000
parents 7da85e0b85e9
children a2ad974b0c8c
files audioio/AudioCallbackPlaySource.cpp audioio/PhaseVocoderTimeStretcher.cpp audioio/PhaseVocoderTimeStretcher.h
diffstat 3 files changed, 24 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/audioio/AudioCallbackPlaySource.cpp	Thu Sep 14 16:08:23 2006 +0000
+++ b/audioio/AudioCallbackPlaySource.cpp	Fri Sep 15 13:35:37 2006 +0000
@@ -603,7 +603,8 @@
 
     if (factor != 1) {
 	PhaseVocoderTimeStretcher *newStretcher = new PhaseVocoderTimeStretcher
-	    (getTargetChannelCount(),
+	    (getTargetSampleRate(),
+             getTargetChannelCount(),
              factor,
              sharpen,
              lrintf(getTargetBlockSize() / factor));
@@ -712,52 +713,6 @@
 
     ts->getOutput(buffer, count);
 
-
-/*!!!
-    for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) {
-
-        RingBuffer<float> *rb = getReadRingBuffer(ch);
-
-        if (rb) {
-
-            float ratio = ts->getRatio();
-
-//            std::cout << "ratio = " << ratio << std::endl;
-
-            size_t available;
-
-            while ((available = ts->getAvailableOutputSamples()) < count) {
-
-                size_t reqd = lrintf((count - available) / ratio);
-                reqd = std::max(reqd, ts->getRequiredInputSamples());
-                if (reqd == 0) reqd = 1;
-
-                float ib[reqd];
-                size_t got = rb->read(ib, reqd);
-
-#ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
-                std::cout << "AudioCallbackPlaySource::getSamples: got " << got << " samples on channel " << ch << " (reqd=" << reqd << ", count=" << count << ", ratio=" << ratio << ", got*ratio=" << got * ratio << "), running time stretcher" << std::endl;
-#endif
-
-                if (got < reqd) {
-                    std::cerr << "WARNING: Read underrun in playback ("
-                              << got << " < " << reqd << ")" << std::endl;
-                }
-                
-                ts->putInput(ib, got);
-
-                if (got == 0) break;
-
-                if (ts->getAvailableOutputSamples() == available) {
-                    std::cerr << "WARNING: AudioCallbackPlaySource::getSamples: Added " << got << " samples to time stretcher, created no new available output samples" << std::endl;
-		    break;
-                }
-            }
-
-            ts->getOutput(buffer[ch], count);
-        }
-    }
-*/
     m_condition.wakeAll();
 
     return count;
--- a/audioio/PhaseVocoderTimeStretcher.cpp	Thu Sep 14 16:08:23 2006 +0000
+++ b/audioio/PhaseVocoderTimeStretcher.cpp	Fri Sep 15 13:35:37 2006 +0000
@@ -20,10 +20,12 @@
 
 //#define DEBUG_PHASE_VOCODER_TIME_STRETCHER 1
 
-PhaseVocoderTimeStretcher::PhaseVocoderTimeStretcher(size_t channels,
+PhaseVocoderTimeStretcher::PhaseVocoderTimeStretcher(size_t sampleRate,
+                                                     size_t channels,
                                                      float ratio,
                                                      bool sharpen,
                                                      size_t maxProcessInputBlockSize) :
+    m_sampleRate(sampleRate),
     m_channels(channels),
     m_ratio(ratio),
     m_sharpen(sharpen),
@@ -35,7 +37,10 @@
 
     //!!! In transient sharpening mode, we need to pick the window
     //length so as to be more or less fixed in audio duration (i.e. we
-    //need to know the sample rate)
+    //need to exploit the sample rate)
+
+    //!!! have to work out the relationship between wlen and transient
+    //threshold
 
     if (ratio < 1) {
         if (ratio < 0.4) {
@@ -65,6 +70,8 @@
         }
         m_n1 = m_n2 / ratio;
     }
+
+    m_transientThreshold = m_wlen / 4.5;
         
     m_analysisWindow = new Window<float>(HanningWindow, m_wlen);
     m_synthesisWindow = new Window<float>(HanningWindow, m_wlen);
@@ -417,7 +424,7 @@
 
     bool isTransient = false;
 
-    if (count > m_wlen / 4.5 && //!!!
+    if (count > m_transientThreshold &&
         count > m_prevTransientScore * 1.2) {
         isTransient = true;
         std::cerr << "isTransient (count = " << count << ", prev = " << m_prevTransientScore << ")" << std::endl;
--- a/audioio/PhaseVocoderTimeStretcher.h	Thu Sep 14 16:08:23 2006 +0000
+++ b/audioio/PhaseVocoderTimeStretcher.h	Fri Sep 15 13:35:37 2006 +0000
@@ -23,17 +23,22 @@
 
 /**
  * A time stretcher that alters the performance speed of audio,
- * preserving pitch.  This uses the simple phase vocoder technique
- * from DAFX pp275-276, adding a block-based stream oriented API.
+ * preserving pitch.
  *
- * Causes significant transient smearing, but sounds good for steady
- * notes and is generally predictable.
+ * This is based on the straightforward phase vocoder with phase
+ * unwrapping (as in e.g. the DAFX book pp275-), with optional
+ * percussive transient detection to avoid smearing percussive notes
+ * and resynchronise phases, and adding a stream API for real-time
+ * use.  Principles and methods from Chris Duxbury, AES 2002 and 2004
+ * thesis; Emmanuel Ravelli, DAFX 2005; Dan Barry, ISSC 2005 on
+ * percussion detection; code by Chris Cannam.
  */
 
 class PhaseVocoderTimeStretcher
 {
 public:
-    PhaseVocoderTimeStretcher(size_t channels,
+    PhaseVocoderTimeStretcher(size_t sampleRate,
+                              size_t channels,
                               float ratio,
                               bool sharpen,
                               size_t maxProcessInputBlockSize);
@@ -131,6 +136,7 @@
     void synthesiseBlock(size_t channel, float *out, float *modulation,
                          size_t lastStep);
 
+    size_t m_sampleRate;
     size_t m_channels;
     float m_ratio;
     bool m_sharpen;
@@ -149,6 +155,7 @@
 
     float *m_prevTransientMag;
     int  m_prevTransientScore;
+    int  m_transientThreshold;
     bool m_prevTransient;
 
     float *m_tempbuf;