Help with TPCircularBuffer: Peek always returns 0
I'm having a hard time understanding how TPCircularBuffer+ABL works (and why it doesn't work when it doesn't). Tried to follow Michael's example in this comment: http://forum.theamazingaudioengine.com/discussion/comment/2207/#Comment_2207
I have an effect processor that requires 512 frame blocks, no more no less. My implementation of the callback looks like this:
TPCircularBufferCopyAudioBufferList(&self->_inCircular, audio, NULL, kTPCircularBufferCopyAll, NULL);
while (TPCircularBufferPeek(&self->_inCircular, NULL, &self->_descr) >= CIRCULAR_BUFFER_FRAMES * 2)
{
AudioBufferList* scratchBuffer = TPCircularBufferPrepareEmptyAudioBufferListWithAudioFormat(&self->_outCircular, &self->_descr, CIRCULAR_BUFFER_FRAMES, NULL);
UInt32 outFrames = CIRCULAR_BUFFER_FRAMES;
TPCircularBufferDequeueBufferListFrames(&self->_inCircular, &outFrames, scratchBuffer, NULL, &self->_descr);
effectProcess(self, scratchBuffer);
TPCircularBufferProduceAudioBufferList(&self->_outCircular, NULL);
}
TPCircularBufferDequeueBufferListFrames(&self->_outCircular, &frames, audio, NULL, &self->_descr);
But what I get is, TPCircularBufferPeek always returning zero.
Could someone help?
P.S. my initialization:
TPCircularBufferInit(&_inCircular, CIRCULAR_BUFFER_FRAMES * _descr.mBytesPerFrame * 2);
TPCircularBufferInit(&_outCircular, CIRCULAR_BUFFER_FRAMES * _descr.mBytesPerFrame * 2);
Comments
Turns out the problem is in the initialization. You need to allow extra bytes above what you think you might need when calling TPCircularBufferInit(). No mentioning of this in the docs unfortunately, a bit confusing.
Another problem was TPCircularBufferPeek() returns the number of audio frames, so you should compare it with just CIRCULAR_BUFFER_FRAMES. My bad.
Good point; added note https://github.com/michaeltyson/TPCircularBuffer/commit/63c2ac7f638f5dcc8169daf7abd078dd27e8bb38
Thanks @Michael.
With 1024 extra it worked fine on my iPhone 6S but didn't work on the iPhone 5! Now with 8192 extra it seems to be working everywhere (including OS X).
I think it would be nice to have a specific safe number or a formula. The side effect of not getting it right is that your filter where you use the circular buffer will simply pass on data unmodified (because Peek returns 0). Is there a safe amount that will work everywhere?
Good question! I wonder what it was about the iPhone 5 that stopped it working...
The 5% measure I proposed in the header comments came from a guesstimate of 256 buffer size, 32-bit noninterleaved stereo:
TPCircularBufferABLBlockHeader
and then the audio dataTPCircularBufferABLBlockHeader
is 96 bytes + one extraAudioBuffer
for noninterleaved audio, which is 16 bytes = 112 bytesNow I think about it, perhaps 15% extra might be a safer suggestion, so that it works with more fragmented audio, or 128 frames...
I'm using 512 frames per channel for FFT, and as it turns out even 1024 extra bytes wasn't enough on the iPhone 5. It's the last 32-bit iPhone afaik, but other than that the same iOS 9.2 etc.
Hmm. What's the total buffer size?
The formula is
CIRCULAR_BUFFER_FRAMES * _descr.mBytesPerFrame * _descr.mChannelsPerFrame + 1024
for both input and output circular buffers. CIRCULAR_BUFFER_FRAMES = 512