Capo 4.1 Now Available

• Chris Liscio

Judging by the release notes (iOS, macOS), the latest minor update to Capo might seem a little thin on changes. There are a few reasons for that.

Generally speaking, I am trying to do a better job splitting releases into more manageable chunks for me to work on. I limit myself to one or two medium-to-large tasks from my backlog, and a few smaller tasks to go along with them.

When selecting these tasks, I also make sure to peel a few tasks off of my “maintenance wishlist” to include in each release. It might sound odd, but it feels good to get these kinds of tasks done. Having them on my list alongside the others makes it easier for me to get started on the next release soon after the last one goes out.

Below are some detailed notes/thoughts about what was added in Capo 4.1.


One of the medium-sized tasks for this release was Handoff support. The initial work to enable Handoff in Capo was very simple, but it opened up a big can of worms. In fact, I tried adding Handoff to Capo in previous releases, but I quickly chickened out when I saw how many other bugs that it triggered.

Adding Handoff to this release isn’t really satisfying any huge demand from our users, but rather I felt it was time to face those other issues head-on with some ample “breathing room” on my side. With Handoff being the only major change, I was confident that any issues found during QA would be easier to resolve.

An added benefit of all this work was that I also resolved a handful of crashes that we had difficulty reproducing before. Something about Handoff triggers a whole bunch of code paths that don’t otherwise get used very frequently.


Adding FLAC support to Capo was another thing that seemed rather simple, but it had a few sharp edges that I needed to take care of. Specifically, most of the work centered around reading FLAC’s metadata.

This turned out to be another one of those tasks that ended up improving Capo in other places. On the Mac, Capo used to rely on a combination of Spotlight, QuickLook, and the iTunesLibrary framework (!) to grab artwork. Metadata for FLAC files isn’t read by those frameworks, so I needed to read it myself.

I was okay with this, because there were many cases where I’d receive a valid image from QuickLook, except it was a generic image that represented “no artwork available”. The trouble is that the file often did contain artwork, but QuickLook just hadn’t pulled the image yet.

Being forced to read directly from FLAC files pushed me to do the same for other file formats. Fortunately, I’ve already done this on iOS because there wasn’t an equivalent system-level API to achieve this at the time.

Anyway, now Capo’s doing a better job grabbing artwork than before. Another win!

Fixing Audio Bugs

This wasn’t part of the plan, but recent reports of re-appearing issues with AirPods was the straw that broke the camel’s back. As I’ve already conveyed in my other posts about AVAudioEngine, I needed to get this resolved correctly once and for all.

Because the audio graph was pretty simple, it only took a day or so to replace my use of AVAudioEngine with some code that directly interfaced with the AUHAL and MultiChannelMixer audio units using the new AUv3 API. This code was far less irritating to write compared to the legacy API, and I am pleased that it all worked out.

Unsurprisingly, this setup has (so far) been well-behaved in the presence of changing audio hardware, AirPods, and even aggregate audio devices. That’s the way it should have worked all along!

Remember, kids: Simplified audio APIs can be more trouble than they’re worth. Hit the books, write a lot of throwaway prototypes to figure out the undocumented stuff, and buckle up for a life filled with pain and heartache.

If it feels easy and straightforward, you’re probably doing it wrong. (If it makes you feel any better, I’ve been doing some form of audio coding for more than 20 years now, and I am frequently doing it wrong.)


It’s looking like Capo 4.2 is going to have another short list of release notes. The big maintenance item that I’m tackling right now is the long-overdue port of my OpenGL-based spectrogram rendering code over to Metal on macOS.

I’ve been putting that work off for too long, but so far it’s not been too bad. I quite enjoy using the Metal APIs, and the debugging tools are mind-blowing.

Back to work I go!