Search code examples
core-audioaudiounitcircular-buffer

Reading chunks of audio with ringbuffer


I would like to analyze chunks of audio data of one second. For this purpose I implemented an audio unit that fills a ringbuffer (TPCircularBuffer by Michael Tyson). In another file I try to read chunks of one second using a NStimer. Unfortunately, I receive errors with consuming these data.

The buffer is filled in a kAudioOutputUnitProperty_SetInputCallback and works fine

Device * THIS = (__bridge Device *)inRefCon;
// Render audio into buffer
AudioBufferList bufferList;
bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mNumberChannels = 2;
bufferList.mBuffers[0].mData = NULL;
bufferList.mBuffers[0].mDataByteSize = inNumberFrames * sizeof(SInt16) * 2;
CheckError(AudioUnitRender(THIS -> rioUnit, ioActionFlags, inTimeStamp, 1, inNumberFrames, &bufferList), "AudioUnitRender");

// Put audio into circular buffer
TPCircularBufferProduceBytes(&circBuffer, bufferList.mBuffers[0].mData, inNumberFrames * 2 * sizeof(SInt16));

To read one second of samples I implemented te following code:

    - (void)initializeTimer {
        timer = [NSTimer scheduledTimerWithTimeInterval:1
                                                 target:self
                                               selector:@selector(timerFired:)
                                               userInfo:nil
                                                repeats:YES];
    }

    - (void) timerFired:(NSTimer *)theTimer {
        NSLog(@"Reading %i second(s) from ring",1);

        int32_t availableBytes;
        SInt16 *tail = TPCircularBufferTail(&circBuffer, &availableBytes);
        int availableSamples = availableBytes / sizeof(SInt16);
        NSLog(@"Available samples %i", availableSamples);

        for (int i = 0; i < availableSamples; i++) {
            printf("%i\n",tail[i]);
        }

        TPCircularBufferConsume(&circBuffer, sizeof(SInt16) * availableBytes);
    }

However, when I run this code the number of samples is printed but then I receive the following error: Assertion failed: (buffer->fillCount >= 0), function TPCircularBufferConsume, file …/TPCircularBuffer.h, line 142.

Unfortunately, I don’t know what is going wrong with consuming the data. The buffer length is set to samplerate * 2 to be long enough.

I would be very happy if someone knows what is going wrong here.


Solution

  • Your circular buffer isn't long enough. You don't check that the available size is positive before emptying, and the time all your print statements take let the buffer get over-filled. Make the buffer at least 2X larger than your timer, check before emptying, empty the buffer before printing, and use far fewer print statements.