diff audioio/AudioCallbackPlaySource.cpp @ 130:4c9c04645685

* Reduce time stretcher to one channel when overload occurs
author Chris Cannam
date Mon, 07 Jul 2008 16:49:53 +0000
parents ab861544f998
children 883f7fc7fd34
line wrap: on
line diff
--- a/audioio/AudioCallbackPlaySource.cpp	Thu Jun 26 12:41:23 2008 +0000
+++ b/audioio/AudioCallbackPlaySource.cpp	Mon Jul 07 16:49:53 2008 +0000
@@ -69,6 +69,7 @@
     m_playStartFrame(0),
     m_playStartFramePassed(false),
     m_timeStretcher(0),
+    m_monoStretcher(0),
     m_stretchRatio(1.0),
     m_stretcherInputCount(0),
     m_stretcherInputs(0),
@@ -122,6 +123,9 @@
     delete[] m_stretcherInputSizes;
     delete[] m_stretcherInputs;
 
+    delete m_timeStretcher;
+    delete m_monoStretcher;
+
     m_bufferScavenger.scavenge(true);
     m_pluginScavenger.scavenge(true);
 }
@@ -388,6 +392,9 @@
     if (m_timeStretcher) {
         m_timeStretcher->reset();
     }
+    if (m_monoStretcher) {
+        m_monoStretcher->reset();
+    }
 
     m_readBufferFill = m_writeBufferFill = startFrame;
     if (m_readBuffers) {
@@ -469,10 +476,24 @@
 void
 AudioCallbackPlaySource::audioProcessingOverload()
 {
+    std::cerr << "Audio processing overload!" << std::endl;
+
+    if (!m_playing) return;
+
     RealTimePluginInstance *ap = m_auditioningPlugin;
-    if (ap && m_playing && !m_auditioningPluginBypassed) {
+    if (ap && !m_auditioningPluginBypassed) {
         m_auditioningPluginBypassed = true;
         emit audioOverloadPluginDisabled();
+        return;
+    }
+
+    if (m_timeStretcher &&
+        m_timeStretcher->getTimeRatio() < 1.0 &&
+        m_stretcherInputCount > 1 &&
+        m_monoStretcher && !m_stretchMono) {
+        m_stretchMono = true;
+        emit audioTimeStretchMultiChannelDisabled();
+        return;
     }
 }
 
@@ -956,23 +977,31 @@
              m_stretcherInputCount,
              RubberBandStretcher::OptionProcessRealTime,
              factor);
+        RubberBandStretcher *monoStretcher = new RubberBandStretcher
+            (getTargetSampleRate(),
+             1,
+             RubberBandStretcher::OptionProcessRealTime,
+             factor);
         m_stretcherInputs = new float *[m_stretcherInputCount];
         m_stretcherInputSizes = new size_t[m_stretcherInputCount];
         for (size_t c = 0; c < m_stretcherInputCount; ++c) {
             m_stretcherInputSizes[c] = 16384;
             m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]];
         }
+        m_monoStretcher = monoStretcher;
         m_timeStretcher = stretcher;
         return;
     }
 }
 
 size_t
-AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer)
+AudioCallbackPlaySource::getSourceSamples(size_t ucount, float **buffer)
 {
+    int count = ucount;
+
     if (!m_playing) {
 	for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) {
-	    for (size_t i = 0; i < count; ++i) {
+	    for (int i = 0; i < count; ++i) {
 		buffer[ch][i] = 0.0;
 	    }
 	}
@@ -1009,6 +1038,8 @@
     if (count == 0) return 0;
 
     RubberBandStretcher *ts = m_timeStretcher;
+    RubberBandStretcher *ms = m_monoStretcher;
+
     float ratio = ts ? ts->getTimeRatio() : 1.f;
 
     if (ratio != m_stretchRatio) {
@@ -1017,6 +1048,18 @@
             m_stretchRatio = 1.f;
         } else {
             ts->setTimeRatio(m_stretchRatio);
+            if (ms) ms->setTimeRatio(m_stretchRatio);
+            if (m_stretchRatio >= 1.0) m_stretchMono = false;
+        }
+    }
+
+    int stretchChannels = m_stretcherInputCount;
+    if (m_stretchMono) {
+        if (ms) {
+            ts = ms;
+            stretchChannels = 1;
+        } else {
+            m_stretchMono = false;
         }
     }
 
@@ -1027,7 +1070,7 @@
 
     if (!ts || ratio == 1.f) {
 
-	size_t got = 0;
+	int got = 0;
 
 	for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) {
 
@@ -1048,7 +1091,7 @@
 	    }
 
 	    for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) {
-		for (size_t i = got; i < count; ++i) {
+		for (int i = got; i < count; ++i) {
 		    buffer[ch][i] = 0.0;
 		}
 	    }
@@ -1082,7 +1125,7 @@
 #endif
 
         for (size_t c = 0; c < channels; ++c) {
-            if (c >= m_stretcherInputCount) continue;
+            if (c >= m_stretcherInputSizes) continue;
             if (reqd > m_stretcherInputSizes[c]) {
                 if (c == 0) {
                     std::cerr << "WARNING: resizing stretcher input buffer from " << m_stretcherInputSizes[c] << " to " << (reqd * 2) << std::endl;
@@ -1094,10 +1137,15 @@
         }
 
         for (size_t c = 0; c < channels; ++c) {
-            if (c >= m_stretcherInputCount) continue;
+            if (c >= m_stretcherInputSizes) continue;
             RingBuffer<float> *rb = getReadRingBuffer(c);
             if (rb) {
-                size_t gotHere = rb->read(m_stretcherInputs[c], got);
+                size_t gotHere;
+                if (stretchChannels == 1 && c > 0) {
+                    gotHere = rb->readAdding(m_stretcherInputs[0], got);
+                } else {
+                    gotHere = rb->read(m_stretcherInputs[c], got);
+                }
                 if (gotHere < got) got = gotHere;
                 
 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
@@ -1131,6 +1179,12 @@
 
     ts->retrieve(buffer, count);
 
+    for (int c = stretchChannels; c < getTargetChannelCount(); ++c) {
+        for (int i = 0; i < count; ++i) {
+            buffer[c][i] = buffer[0][i];
+        }
+    }
+
     applyAuditioningEffect(count, buffer);
 
     m_condition.wakeAll();