changeset 106:f8e362511b2f

* Probable fix to occasional channel misalignment during playback
author Chris Cannam
date Mon, 26 Feb 2007 16:32:37 +0000
parents 0581d552481d
children dd11619b73ba
files audioio/AudioCallbackPlaySource.cpp audioio/AudioJACKTarget.cpp audioio/AudioPortAudioTarget.cpp
diffstat 3 files changed, 91 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/audioio/AudioCallbackPlaySource.cpp	Mon Feb 26 14:55:08 2007 +0000
+++ b/audioio/AudioCallbackPlaySource.cpp	Mon Feb 26 16:32:37 2007 +0000
@@ -126,7 +126,7 @@
 	m_sourceChannelCount = modelChannels;
     }
 
-//    std::cerr << "Adding model with " << modelChannels << " channels " << std::endl;
+//    std::cout << "Adding model with " << modelChannels << " channels " << std::endl;
 
     if (m_sourceSampleRate == 0) {
 
@@ -195,7 +195,7 @@
     }
 
 #ifdef DEBUG_AUDIO_PLAY_SOURCE
-    std::cerr << "AudioCallbackPlaySource::addModel: emitting modelReplaced" << std::endl;
+    std::cout << "AudioCallbackPlaySource::addModel: emitting modelReplaced" << std::endl;
 #endif
 
     if (buffersChanged || srChanged) {
@@ -225,9 +225,9 @@
     size_t lastEnd = 0;
     for (std::set<Model *>::const_iterator i = m_models.begin();
 	 i != m_models.end(); ++i) {
-//	std::cerr << "AudioCallbackPlaySource::removeModel(" << model << "): checking end frame on model " << *i << std::endl;
+//	std::cout << "AudioCallbackPlaySource::removeModel(" << model << "): checking end frame on model " << *i << std::endl;
 	if ((*i)->getEndFrame() > lastEnd) lastEnd = (*i)->getEndFrame();
-//	std::cerr << "(done, lastEnd now " << lastEnd << ")" << std::endl;
+//	std::cout << "(done, lastEnd now " << lastEnd << ")" << std::endl;
     }
     m_lastModelEndFrame = lastEnd;
 
@@ -293,7 +293,7 @@
 	m_writeBuffers->push_back(new RingBuffer<float>(m_ringBufferSize));
     }
 
-//    std::cerr << "AudioCallbackPlaySource::clearRingBuffers: Created "
+//    std::cout << "AudioCallbackPlaySource::clearRingBuffers: Created "
 //	      << count << " write buffers" << std::endl;
 
     if (!haveLock) {
@@ -413,7 +413,7 @@
 void
 AudioCallbackPlaySource::setTargetBlockSize(size_t size)
 {
-//    std::cerr << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl;
+//    std::cout << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl;
     assert(size < m_ringBufferSize);
     m_blockSize = size;
 }
@@ -421,7 +421,7 @@
 size_t
 AudioCallbackPlaySource::getTargetBlockSize() const
 {
-//    std::cerr << "AudioCallbackPlaySource::getTargetBlockSize() -> " << m_blockSize << std::endl;
+//    std::cout << "AudioCallbackPlaySource::getTargetBlockSize() -> " << m_blockSize << std::endl;
     return m_blockSize;
 }
 
@@ -509,28 +509,28 @@
 
     size_t f = bufferedFrame;
 
-//    std::cerr << "getCurrentPlayingFrame: f=" << f << ", latency=" << latency << ", rangeEnd=" << rangeEnd << std::endl;
+//    std::cout << "getCurrentPlayingFrame: f=" << f << ", latency=" << latency << ", rangeEnd=" << rangeEnd << std::endl;
 
     if (i == selections.end()) {
 	--i;
 	if (i->getEndFrame() + latency < f) {
-//    std::cerr << "framePlaying = " << framePlaying << ", rangeEnd = " << rangeEnd << std::endl;
+//    std::cout << "framePlaying = " << framePlaying << ", rangeEnd = " << rangeEnd << std::endl;
 
 	    if (!looping && (framePlaying > rangeEnd)) {
-//		std::cerr << "STOPPING" << std::endl;
+//		std::cout << "STOPPING" << std::endl;
 		stop();
 		return rangeEnd;
 	    } else {
 		return framePlaying;
 	    }
 	} else {
-//	    std::cerr << "latency <- " << latency << "-(" << f << "-" << i->getEndFrame() << ")" << std::endl;
+//	    std::cout << "latency <- " << latency << "-(" << f << "-" << i->getEndFrame() << ")" << std::endl;
 	    latency -= (f - i->getEndFrame());
 	    f = i->getEndFrame();
 	}
     }
 
-//    std::cerr << "i=(" << i->getStartFrame() << "," << i->getEndFrame() << ") f=" << f << ", latency=" << latency << std::endl;
+//    std::cout << "i=(" << i->getStartFrame() << "," << i->getEndFrame() << ") f=" << f << ", latency=" << latency << std::endl;
 
     while (latency > 0) {
 	size_t offset = f - i->getStartFrame();
@@ -745,6 +745,35 @@
 	return 0;
     }
 
+    // Ensure that all buffers have at least the amount of data we
+    // need -- else reduce the size of our requests correspondingly
+
+    for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) {
+
+        RingBuffer<float> *rb = getReadRingBuffer(ch);
+        
+        if (!rb) {
+            std::cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: "
+                      << "No ring buffer available for channel " << ch
+                      << ", returning no data here" << std::endl;
+            count = 0;
+            break;
+        }
+
+        size_t rs = rb->getReadSpace();
+        if (rs < count) {
+#ifdef DEBUG_AUDIO_PLAY_SOURCE
+            std::cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: "
+                      << "Ring buffer for channel " << ch << " has only "
+                      << rs << " (of " << count << ") samples available, "
+                      << "reducing request size" << std::endl;
+#endif
+            count = rs;
+        }
+    }
+
+    if (count == 0) return 0;
+
     PhaseVocoderTimeStretcher *ts = m_timeStretcher;
 
     if (!ts || ts->getRatio() == 1) {
@@ -765,7 +794,7 @@
 		got = rb->read(buffer[ch], request);
 	    
 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
-		std::cout << "AudioCallbackPlaySource::getSamples: got " << got << " samples on channel " << ch << ", signalling for more (possibly)" << std::endl;
+		std::cout << "AudioCallbackPlaySource::getSamples: got " << got << " (of " << count << ") samples on channel " << ch << ", signalling for more (possibly)" << std::endl;
 #endif
 	    }
 
@@ -1042,7 +1071,7 @@
 
         if (m_timeStretcher && m_timeStretcher->getRatio() < 0.4) {
 #ifdef DEBUG_AUDIO_PLAY_SOURCE
-            std::cerr << "Using crappy converter" << std::endl;
+            std::cout << "Using crappy converter" << std::endl;
 #endif
             src_process(m_crapConverter, &data);
         } else {
@@ -1060,7 +1089,7 @@
 	    got = data.input_frames_used;
 	    toCopy = data.output_frames_gen;
 #ifdef DEBUG_AUDIO_PLAY_SOURCE
-	    std::cerr << "Resampled " << got << " frames to " << toCopy << " frames" << std::endl;
+	    std::cout << "Resampled " << got << " frames to " << toCopy << " frames" << std::endl;
 #endif
 	}
 	
@@ -1101,14 +1130,19 @@
 	for (size_t c = 0; c < channels; ++c) {
 
 	    RingBuffer<float> *wb = getWriteRingBuffer(c);
-	    if (wb) wb->write(bufferPtrs[c], got);
-
+	    if (wb) {
+                size_t actual = wb->write(bufferPtrs[c], got);
 #ifdef DEBUG_AUDIO_PLAY_SOURCE
-	    if (wb)
-		std::cerr << "Wrote " << got << " frames for ch " << c << ", now "
+		std::cout << "Wrote " << actual << " samples for ch " << c << ", now "
 			  << wb->getReadSpace() << " to read" 
 			  << std::endl;
 #endif
+                if (actual < got) {
+                    std::cerr << "WARNING: Buffer overrun in channel " << c
+                              << ": wrote " << actual << " of " << got
+                              << " samples" << std::endl;
+                }
+            }
 	}
 
 	m_writeBufferFill = f;
@@ -1138,7 +1172,7 @@
     size_t channels = getTargetChannelCount();
 
 #ifdef DEBUG_AUDIO_PLAY_SOURCE
-    std::cerr << "Selection playback: start " << frame << ", size " << count <<", channels " << channels << std::endl;
+    std::cout << "Selection playback: start " << frame << ", size " << count <<", channels " << channels << std::endl;
 #endif
 
     if (chunkBufferPtrCount < channels) {
@@ -1209,11 +1243,11 @@
 	    nextChunkStart = chunkStart + chunkSize;
 	}
 	
-//	std::cerr << "chunkStart " << chunkStart << ", chunkSize " << chunkSize << ", nextChunkStart " << nextChunkStart << ", frame " << frame << ", count " << count << ", processed " << processed << std::endl;
+//	std::cout << "chunkStart " << chunkStart << ", chunkSize " << chunkSize << ", nextChunkStart " << nextChunkStart << ", frame " << frame << ", count " << count << ", processed " << processed << std::endl;
 
 	if (!chunkSize) {
 #ifdef DEBUG_AUDIO_PLAY_SOURCE
-	    std::cerr << "Ending selection playback at " << nextChunkStart << std::endl;
+	    std::cout << "Ending selection playback at " << nextChunkStart << std::endl;
 #endif
 	    // We need to maintain full buffers so that the other
 	    // thread can tell where it's got to in the playback -- so
@@ -1223,7 +1257,7 @@
 	}
 
 #ifdef DEBUG_AUDIO_PLAY_SOURCE
-	std::cerr << "Selection playback: chunk at " << chunkStart << " -> " << nextChunkStart << " (size " << chunkSize << ")" << std::endl;
+	std::cout << "Selection playback: chunk at " << chunkStart << " -> " << nextChunkStart << " (size " << chunkSize << ")" << std::endl;
 #endif
 
 	size_t got = 0;
@@ -1265,7 +1299,7 @@
     }
 
 #ifdef DEBUG_AUDIO_PLAY_SOURCE
-    std::cerr << "Returning selection playback " << processed << " frames to " << nextChunkStart << std::endl;
+    std::cout << "Returning selection playback " << processed << " frames to " << nextChunkStart << std::endl;
 #endif
 
     frame = nextChunkStart;
@@ -1298,12 +1332,12 @@
     if (rb) {
 	size_t rs = rb->getReadSpace();
 	//!!! incorrect when in non-contiguous selection, see comments elsewhere
-//	std::cerr << "rs = " << rs << std::endl;
+//	std::cout << "rs = " << rs << std::endl;
 	if (rs < rf) rf -= rs;
 	else rf = 0;
     }
     
-    //std::cerr << "m_readBufferFill = " << m_readBufferFill << ", rf = " << rf << ", m_writeBufferFill = " << m_writeBufferFill << std::endl;
+    //std::cout << "m_readBufferFill = " << m_readBufferFill << ", rf = " << rf << ", m_writeBufferFill = " << m_writeBufferFill << std::endl;
 
     size_t wf = m_writeBufferFill;
     size_t skip = 0;
@@ -1313,17 +1347,17 @@
 	    if (c == 0) {
 		
 		size_t wrs = wb->getReadSpace();
-//		std::cerr << "wrs = " << wrs << std::endl;
+//		std::cout << "wrs = " << wrs << std::endl;
 
 		if (wrs < wf) wf -= wrs;
 		else wf = 0;
-//		std::cerr << "wf = " << wf << std::endl;
+//		std::cout << "wf = " << wf << std::endl;
 		
 		if (wf < rf) skip = rf - wf;
 		if (skip == 0) break;
 	    }
 
-//	    std::cerr << "skipping " << skip << std::endl;
+//	    std::cout << "skipping " << skip << std::endl;
 	    wb->skip(skip);
 	}
     }
@@ -1331,7 +1365,7 @@
     m_bufferScavenger.claim(m_readBuffers);
     m_readBuffers = m_writeBuffers;
     m_readBufferFill = m_writeBufferFill;
-//    std::cerr << "unified" << std::endl;
+//    std::cout << "unified" << std::endl;
 }
 
 void
@@ -1340,7 +1374,7 @@
     AudioCallbackPlaySource &s(m_source);
     
 #ifdef DEBUG_AUDIO_PLAY_SOURCE
-    std::cerr << "AudioCallbackPlaySourceFillThread starting" << std::endl;
+    std::cout << "AudioCallbackPlaySourceFillThread starting" << std::endl;
 #endif
 
     s.m_mutex.lock();
@@ -1372,8 +1406,9 @@
 	    }
 	    
 	    if (s.m_playing) ms /= 10;
-	    
+
 #ifdef DEBUG_AUDIO_PLAY_SOURCE
+            if (!s.m_playing) std::cout << std::endl;
 	    std::cout << "AudioCallbackPlaySourceFillThread: waiting for " << ms << "ms..." << std::endl;
 #endif
 	    
--- a/audioio/AudioJACKTarget.cpp	Mon Feb 26 14:55:08 2007 +0000
+++ b/audioio/AudioJACKTarget.cpp	Mon Feb 26 16:32:37 2007 +0000
@@ -352,14 +352,16 @@
 	buffers[ch] = (float *)jack_port_get_buffer(m_outputs[ch], nframes);
     }
 
+    size_t received = 0;
+
     if (m_source) {
-	m_source->getSourceSamples(nframes, buffers);
-    } else {
-	for (size_t ch = 0; ch < m_outputs.size(); ++ch) {
-	    for (size_t i = 0; i < nframes; ++i) {
-		buffers[ch][i] = 0.0;
-	    }
-	}
+	received = m_source->getSourceSamples(nframes, buffers);
+    }
+
+    for (size_t ch = 0; ch < m_outputs.size(); ++ch) {
+        for (size_t i = received; i < nframes; ++i) {
+            buffers[ch][i] = 0.0;
+        }
     }
 
     float peakLeft = 0.0, peakRight = 0.0;
--- a/audioio/AudioPortAudioTarget.cpp	Mon Feb 26 14:55:08 2007 +0000
+++ b/audioio/AudioPortAudioTarget.cpp	Mon Feb 26 16:32:37 2007 +0000
@@ -202,7 +202,7 @@
 	}
     }
 	
-    m_source->getSourceSamples(nframes, tmpbuf);
+    size_t received = m_source->getSourceSamples(nframes, tmpbuf);
 
     float peakLeft = 0.0, peakRight = 0.0;
 
@@ -214,17 +214,25 @@
 
 	    // PortAudio samples are interleaved
 	    for (size_t i = 0; i < nframes; ++i) {
-		output[i * 2 + ch] = tmpbuf[ch][i] * m_outputGain;
-		float sample = fabsf(output[i * 2 + ch]);
-		if (sample > peak) peak = sample;
+                if (i < received) {
+                    output[i * 2 + ch] = tmpbuf[ch][i] * m_outputGain;
+                    float sample = fabsf(output[i * 2 + ch]);
+                    if (sample > peak) peak = sample;
+                } else {
+                    output[i * 2 + ch] = 0;
+                }
 	    }
 
 	} else if (ch == 1 && sourceChannels == 1) {
 
 	    for (size_t i = 0; i < nframes; ++i) {
-		output[i * 2 + ch] = tmpbuf[0][i] * m_outputGain;
-		float sample = fabsf(output[i * 2 + ch]);
-		if (sample > peak) peak = sample;
+                if (i < received) {
+                    output[i * 2 + ch] = tmpbuf[0][i] * m_outputGain;
+                    float sample = fabsf(output[i * 2 + ch]);
+                    if (sample > peak) peak = sample;
+                } else {
+                    output[i * 2 + ch] = 0;
+                }
 	    }
 
 	} else {