Mercurial > hg > svapp
diff audioio/AudioCallbackPlaySource.cpp @ 13:89bb89894ad6
* As previous commit
author | Chris Cannam |
---|---|
date | Fri, 17 Feb 2006 18:11:08 +0000 |
parents | 29b38a641d43 |
children | 6b5eaf206f0f |
line wrap: on
line diff
--- a/audioio/AudioCallbackPlaySource.cpp Fri Feb 17 18:04:26 2006 +0000 +++ b/audioio/AudioCallbackPlaySource.cpp Fri Feb 17 18:11:08 2006 +0000 @@ -22,6 +22,7 @@ #include <cassert> //#define DEBUG_AUDIO_PLAY_SOURCE 1 +//#define DEBUG_AUDIO_PLAY_SOURCE_PLAYING 1 //const size_t AudioCallbackPlaySource::m_ringBufferSize = 102400; const size_t AudioCallbackPlaySource::m_ringBufferSize = 131071; @@ -31,6 +32,9 @@ m_audioGenerator(new AudioGenerator(manager)), m_readBuffers(0), m_writeBuffers(0), + m_readBufferFill(0), + m_writeBufferFill(0), + m_bufferScavenger(1), m_sourceChannelCount(0), m_blockSize(1024), m_sourceSampleRate(0), @@ -38,7 +42,6 @@ m_playLatency(0), m_playing(false), m_exiting(false), - m_bufferedToFrame(0), m_lastModelEndFrame(0), m_outputLeft(0.0), m_outputRight(0.0), @@ -119,12 +122,8 @@ std::cerr << "Adding model with " << modelChannels << " channels " << std::endl; - if (!m_writeBuffers || m_writeBuffers->size() < modelChannels) { - m_audioGenerator->setTargetChannelCount(modelChannels); - } - - if (!m_writeBuffers || (m_writeBuffers->size() < modelChannels)) { - clearRingBuffers(true, modelChannels); + if (!m_writeBuffers || (m_writeBuffers->size() < getTargetChannelCount())) { + clearRingBuffers(true, getTargetChannelCount()); buffersChanged = true; } else { if (canPlay) clearRingBuffers(true); @@ -139,6 +138,8 @@ m_mutex.unlock(); + m_audioGenerator->setTargetChannelCount(getTargetChannelCount()); + if (!m_fillThread) { m_fillThread = new AudioCallbackPlaySourceFillThread(*this); m_fillThread->start(); @@ -214,6 +215,19 @@ if (m_writeBuffers) count = m_writeBuffers->size(); } + size_t sf = m_readBufferFill; + RingBuffer<float> *rb = getReadRingBuffer(0); + if (rb) { + //!!! This is incorrect if we're in a non-contiguous selection + //Same goes for all related code (subtracting the read space + //from the fill frame to try to establish where the effective + //pre-resample/timestretch read pointer is) + size_t rs = rb->getReadSpace(); + if (rs < sf) sf -= rs; + else sf = 0; + } + m_writeBufferFill = sf; + if (m_readBuffers != m_writeBuffers) { delete m_writeBuffers; } @@ -263,9 +277,9 @@ m_mutex.lock(); if (m_playing) { - m_bufferedToFrame = startFrame; + m_readBufferFill = m_writeBufferFill = startFrame; if (m_readBuffers) { - for (size_t c = 0; c < getSourceChannelCount(); ++c) { + for (size_t c = 0; c < getTargetChannelCount(); ++c) { RingBuffer<float> *rb = getReadRingBuffer(c); if (rb) rb->reset(); } @@ -273,7 +287,7 @@ if (m_converter) src_reset(m_converter); } else { if (m_converter) src_reset(m_converter); - m_bufferedToFrame = startFrame; + m_readBufferFill = m_writeBufferFill = startFrame; } m_mutex.unlock(); @@ -359,7 +373,7 @@ } size_t readSpace = 0; - for (size_t c = 0; c < getSourceChannelCount(); ++c) { + for (size_t c = 0; c < getTargetChannelCount(); ++c) { RingBuffer<float> *rb = getReadRingBuffer(c); if (rb) { size_t spaceHere = rb->getReadSpace(); @@ -380,7 +394,7 @@ } latency += readSpace; - size_t bufferedFrame = m_bufferedToFrame; + size_t bufferedFrame = m_readBufferFill; bool looping = m_viewManager->getPlayLoopMode(); bool constrained = (m_viewManager->getPlaySelectionMode() && @@ -489,7 +503,8 @@ if (getSourceSampleRate() != getTargetSampleRate()) { int err = 0; - m_converter = src_new(SRC_SINC_BEST_QUALITY, m_sourceChannelCount, &err); + m_converter = src_new(SRC_SINC_BEST_QUALITY, + getTargetChannelCount(), &err); if (!m_converter) { std::cerr << "AudioCallbackPlaySource::setModel: ERROR in creating samplerate converter: " @@ -514,6 +529,13 @@ } size_t +AudioCallbackPlaySource::getTargetChannelCount() const +{ + if (m_sourceChannelCount < 2) return 2; + return m_sourceChannelCount; +} + +size_t AudioCallbackPlaySource::getSourceSampleRate() const { return m_sourceSampleRate; @@ -590,7 +612,7 @@ if (factor > 1) { TimeStretcherData *newStretcher = new TimeStretcherData - (getSourceChannelCount(), factor, getTargetBlockSize()); + (getTargetChannelCount(), factor, getTargetBlockSize()); m_slowdownCounter = 0; m_timeStretcher = newStretcher; } else { @@ -606,7 +628,7 @@ AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer) { if (!m_playing) { - for (size_t ch = 0; ch < getSourceChannelCount(); ++ch) { + for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { for (size_t i = 0; i < count; ++i) { buffer[ch][i] = 0.0; } @@ -620,7 +642,7 @@ size_t got = 0; - for (size_t ch = 0; ch < getSourceChannelCount(); ++ch) { + for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { RingBuffer<float> *rb = getReadRingBuffer(ch); @@ -638,7 +660,7 @@ #endif } - for (size_t ch = 0; ch < getSourceChannelCount(); ++ch) { + for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { for (size_t i = got; i < count; ++i) { buffer[ch][i] = 0.0; } @@ -654,7 +676,7 @@ size_t got = 0; double *ib = timeStretcher->getInputBuffer(); - for (size_t ch = 0; ch < getSourceChannelCount(); ++ch) { + for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { RingBuffer<float> *rb = getReadRingBuffer(ch); @@ -682,7 +704,7 @@ m_slowdownCounter = 0; } - for (size_t ch = 0; ch < getSourceChannelCount(); ++ch) { + for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { double *ob = timeStretcher->getOutputBuffer(ch); @@ -708,7 +730,7 @@ static size_t tmpSize = 0; size_t space = 0; - for (size_t c = 0; c < getSourceChannelCount(); ++c) { + for (size_t c = 0; c < getTargetChannelCount(); ++c) { RingBuffer<float> *wb = getWriteRingBuffer(c); if (wb) { size_t spaceHere = wb->getWriteSpace(); @@ -718,12 +740,14 @@ if (space == 0) return false; + size_t f = m_writeBufferFill; + + bool readWriteEqual = (m_readBuffers == m_writeBuffers); + #ifdef DEBUG_AUDIO_PLAY_SOURCE std::cout << "AudioCallbackPlaySourceFillThread: filling " << space << " frames" << std::endl; #endif - size_t f = m_bufferedToFrame; - #ifdef DEBUG_AUDIO_PLAY_SOURCE std::cout << "buffered to " << f << " already" << std::endl; #endif @@ -734,7 +758,8 @@ std::cout << (resample ? "" : "not ") << "resampling (source " << getSourceSampleRate() << ", target " << getTargetSampleRate() << ")" << std::endl; #endif - size_t channels = getSourceChannelCount(); + size_t channels = getTargetChannelCount(); + size_t orig = space; size_t got = 0; @@ -843,8 +868,9 @@ if (wb) wb->write(tmp, toCopy); } - m_bufferedToFrame = f; - + m_writeBufferFill = f; + if (readWriteEqual) m_readBufferFill = f; + } else { // space must be a multiple of generatorBlockSize @@ -881,7 +907,9 @@ #endif } - m_bufferedToFrame = f; + m_writeBufferFill = f; + if (readWriteEqual) m_readBufferFill = f; + //!!! how do we know when ended? need to mark up a fully-buffered flag and check this if we find the buffers empty in getSourceSamples } @@ -903,7 +931,7 @@ static float **chunkBufferPtrs = 0; static size_t chunkBufferPtrCount = 0; - size_t channels = getSourceChannelCount(); + size_t channels = getTargetChannelCount(); #ifdef DEBUG_AUDIO_PLAY_SOURCE std::cerr << "Selection playback: start " << frame << ", size " << count <<", channels " << channels << std::endl; @@ -1041,6 +1069,68 @@ } void +AudioCallbackPlaySource::unifyRingBuffers() +{ + if (m_readBuffers == m_writeBuffers) return; + + // only unify if there will be something to read + for (size_t c = 0; c < getTargetChannelCount(); ++c) { + RingBuffer<float> *wb = getWriteRingBuffer(c); + if (wb) { + if (wb->getReadSpace() < m_blockSize * 2) { + if ((m_writeBufferFill + m_blockSize * 2) < + m_lastModelEndFrame) { + // OK, we don't have enough and there's more to + // read -- don't unify until we can do better + return; + } + } + break; + } + } + + size_t rf = m_readBufferFill; + RingBuffer<float> *rb = getReadRingBuffer(0); + if (rb) { + size_t rs = rb->getReadSpace(); + //!!! incorrect when in non-contiguous selection, see comments elsewhere +// std::cerr << "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; + + size_t wf = m_writeBufferFill; + size_t skip = 0; + for (size_t c = 0; c < getTargetChannelCount(); ++c) { + RingBuffer<float> *wb = getWriteRingBuffer(c); + if (wb) { + if (c == 0) { + + size_t wrs = wb->getReadSpace(); +// std::cerr << "wrs = " << wrs << std::endl; + + if (wrs < wf) wf -= wrs; + else wf = 0; +// std::cerr << "wf = " << wf << std::endl; + + if (wf < rf) skip = rf - wf; + if (skip == 0) break; + } + +// std::cerr << "skipping " << skip << std::endl; + wb->skip(skip); + } + } + + m_bufferScavenger.claim(m_readBuffers); + m_readBuffers = m_writeBuffers; + m_readBufferFill = m_writeBufferFill; + std::cerr << "unified" << std::endl; +} + +void AudioCallbackPlaySource::AudioCallbackPlaySourceFillThread::run() { AudioCallbackPlaySource &s(m_source); @@ -1056,12 +1146,7 @@ while (!s.m_exiting) { - if (s.m_readBuffers != s.m_writeBuffers) { - s.m_bufferScavenger.claim(s.m_readBuffers); - s.m_readBuffers = s.m_writeBuffers; - std::cerr << "unified" << std::endl; - } - + s.unifyRingBuffers(); s.m_bufferScavenger.scavenge(); s.m_timeStretcherScavenger.scavenge(); @@ -1100,7 +1185,7 @@ #ifdef DEBUG_AUDIO_PLAY_SOURCE std::cout << "AudioCallbackPlaySourceFillThread: playback state changed, resetting" << std::endl; #endif - for (size_t c = 0; c < s.getSourceChannelCount(); ++c) { + for (size_t c = 0; c < s.getTargetChannelCount(); ++c) { RingBuffer<float> *rb = s.getReadRingBuffer(c); if (rb) rb->reset(); }