Page 1 of 1

Circle Audio Buffering

Posted: Mon Sep 17, 2018 7:26 pm
by thomas_lee
This is my first post in the forum, so first would just like to thank everyone who have been working on Circle. The process getting it to work was super simple and I've been able to cross-compile bundled examples without issues.

Anyway, I'm new to Circle and would like to understand better how the audio system works. I have modified the miniorgan example so support more advanced audio synthesis and things kind of work, but i have noticed that GetNextChunk() should return fairly quickly or there's corrupted output.

I'm using the default buffer size 2048 (which should translate to 23ms worth of audio stream?) and I thought it would be ok to spend up to 23ms in generating the buffer which should be plenty of time given the CPU speed on pi3 b+. However, If I add anything more complex than few sin(x) I start to get corrupted output so I was thinking is there some limit for processing time caused by the interrupts/DMA system that would require GetNextChunk() return much quicker than in 23ms max.

Any help or guidance would be appreciated. I'm new to Raspberry PI and Circle so bare with me if these should be obvious :)

Re: Circle Audio Buffering

Posted: Tue Sep 18, 2018 10:54 am
by rst
Supposing you are using the PWM sound device at 44.1 KHz sample rate, writing out one sound DMA buffer with 2048 samples (1024 per channel) should take about 23 ms, as you have noted. The CPWMSoundBaseDevice class uses two of these linked sound DMA buffers, so that while one buffer is written out, the other can be filled by the application in GetChunk().

If you have to do complex operations to prepare the sound data, 23 ms may be not much. Additionally there may be some overhead to handle the DMA interrupt at the end of the transmission of each sound buffer and to manage the data cache, which is required to ensure, the sound data can be written out using DMA. Unfortunately I cannot specify, how much overhead this will take, without doing complex measurements, but I guess it will be not more than a few milliseconds.

So what can you do? If possible, you could increase the nChunkSize parameter from 2048. This will reduce the influence of the overhead needed for the DMA interrupt and you will have more time to fill in the sound buffer (of course you have to produce more sound samples in this time then).

Another possibility is to use the multi-core capabilities of the RPi 3B+ to render the sound data. This is more complex, but very helpful. You may have a look at my MiniSynth Pi project, which is a virtual analog audio synthesizer based on Circle. The calculations needed for the VCF (filter) have been time consuming too. MiniSynth Pi can generate 24 simultaneous voices on the RPi 2, 3B and 3B+ using multi-core. On the RPi 1 it can generate only 4 simultaneous voices.

Re: Circle Audio Buffering

Posted: Tue Sep 18, 2018 7:22 pm
by thomas_lee
Thanks a lot for your good explanation and confirming that the double buffering should indeed work as expected so it's most likely just the overhead from DMA and non-optimized code on my side that's the issue (developed the synth originally for high-end PCs). The idea of using other cores of doing calculations makes lots of sense and your Minisynth PI project is super helpful in understanding how everything fits together and as a benchmark.

Thanks a lot!

Re: Circle Audio Buffering

Posted: Wed Sep 19, 2018 10:31 am
by rst
You are welcome. I did some measurements now and it comes out, that my guess was far too pessimistic. On a RPi 3B+ the overhead for DMA interrupt and cache management is safely below 30 microseconds per chunk. So the influence of this overhead on the available time for rendering the sound data is minimal.