Click Life

Hi. So I just submitted a couple of Loop Find updates (version 1.1.1 and 1.1.2) that fix some bonehead audio bugs I made. I thought it may be worth sharing a little though, because these are easy mistakes, and this provides some evidence to back up the conventional wisdom we hear about real time programming.

The first is an interpolation error. I use cubic interpolation to resample the samples in Loop Find. It's a 3rd order B-Spline. So the actual implementation requires 4 samples, starting one place to the left of the currently required sample. That helps it to be more accurate, sound nicer.

So at the beginning of sample playback, you need to handle the negative sample on the left; when it plays the end of the sample you need to handle 2 trailing samples that reach over the end of the sample buffer, on the right (what is a sample?). Otherwise you will reach outside of your buffer and be grabbing unknown data, and using that for playback. I did the second one, I was not assigning zeros in place of the overflowing samples at the end.

I would've thought such a thing easy to detect, because it would pop and click, but because of the way memory in my app is structured, those dangling samples at the end of the buffer would be zeros (so, harmless) unless the next track was playing. So the bug would exhibit itself only when these conditions were true.

  1. A sample pad was playing the end of it's sample.

  2. The next sample pad was playing.

That was bad enough. The other thing that was causing some clicking was something called dispatch_async( ). When I start playing a sample on the real-time audio thread, I have to signal the main thread so it can update the UI. I was doing that by queuing a block of code on the main runtime loop, using a function called dispatch_async( ). Don't do that. I thought it would be okay, and have done it sparingly in the past, even though I had been advised that the function does do some allocation, and therefore is not safe to use on the real-time thread.

So the bug was not very consistent, but once I had started building songs that had a whole bunch of samples triggering and automating a bunch of things, it started popping up enough that I noticed it, and dedeuced that it was likely do to those asynchronous GCD calls. They are doing allocations, and are not safe to use from the audio thread, or so was asserted in this WWDC 2015 session talk (https://developer.apple.com/videos/play/wwdc2015/508/).

So yeah, don't do these things. I had to just poll the state of the samplers, with an NSTimer, from another thread, and update the UI when something changes, which solved the problem.

Edit: Changed wording, Grammer. Added sample link. Math error…