Friday 17 January 2014

Memory Playback

One of the techniques BitPerfect uses to maximize playback sound quality is to play from RAM memory. Most music players will play directly from the music file. The advantage of that method is that you only read the music data from the file as you need it, and stream it to the audio output device. If you change your mind and decide to play something else, or move playback to a different part of the track, that is easy to accomplish - at least from a programming simplicity perspective - using that method.

BitPerfect instead takes advantage of the phenomenal processing power of a modern computer and pre-loads the music into a RAM buffer. When you want to play the music, you simply pass the “address” of the RAM buffer to the audio output device, and it automatically handles the rest. In order for this to be practical, you must be able to not only read the file, decode it, and load the music data into the buffer, but also perform any manipulation that might be necessary, such as sample rate conversion, all in double-quick time.

So how practical is this? Surprisingly so, it turns out. Here is a peg in the ground taken from the totally basic 2013 Mac Mini I use in our reference system. It has a 2.5GHz Core i5 processor, and 4GB of system RAM. I allocate 512MB of RAM for the audio buffers. For this test I have BitPerfect set to upsample from 44.1kHz to 176.4kHz and (for purposes of full disclosure) I am using the as-yet unreleased version 1.1 of BitPerfect which has a new and improved 64-bit audio engine. Using this system, a piece of music of 1 minute 35 seconds duration, is read from an Apple Lossless file, decoded, upsampled to 176.4kHz, and loaded into its RAM buffer in only 1.9 seconds.

There are many advantages to doing it this way, and one of those is the ability to minimize CPU time during playback. In the early days of BitPerfect we discovered that reducing the CPU time tended to have an improving effect on sound quality. More recently we have established that it is only certain kinds of CPU activity that have this effect, but nonetheless, minimizing “undesirable” CPU load is one BitPerfect’s key goals in improving playback quality.

BitPerfect is able to start playing the track as soon as you start loading it into the buffer, so playback commences pretty much instantly, and the loading of the track continues during the first 1.9 seconds of playback. Beyond that, BitPerfect requires CPU cycles only for the direct management of playback. In principle, then, there exists the possibility that the sound quality of playback is degraded slightly by the additional CPU load during those first 1.9 seconds, but frankly, we know of nobody who has been able to detect this audibly. Certainly, we can’t. However, for the remaining 1 minute 33 seconds, playback will be at BitPerfect’s highest caliber.

What happens if the track is too big to fit into the buffer? No problem. The RAM that you allocate in BitPerfect’s Preferences menu is actually equally divided into two buffers. If the whole track does not fit into the first buffer, the remainder is put into the second buffer. As soon as the contents of the first buffer finishes playing, playback is instantaneously switched to the second buffer. The switching occupies only a tiny fraction of the time interval between consecutive samples, so the audio output device does not even know it is happening. And if the track still does not fit into two buffers, then as soon as the first buffer finishes playing and playback switches to the second buffer, the remaining unplayed content is loaded into the first buffer. BitPerfect can do this ad infinitum, in effect maintaining the two buffers as a “wash and wear” pair, with one in use and the other containing whatever is up next.

This has important ramifications for those who like to claim that lossless music encoded in different formats, such as WAV, AIFF, FLAC, and Apple Lossless, all sound different. Of those three formats, the third and fourth are losslessly compressed. Like unzipping a ZIP file, they need to be decoded after opening before they can be played. But after decoding, their contents are absolutely identical (“bit perfect”, if you like) to the contents of the uncompressed WAV or AIFF file. I suppose there is room for playback of a losslessly compressed file to sound different to a WAV/AIFF file if you make the assumption that the additional processing involved in decoding the file results in some kind of audible degradation. But either way, if you are playing those files using BitPerfect, then once the 1.9 second buffer load is over, then there is nothing left that would be in any way different depending on whether the music data had originally been extracted from a WAV, AIFF, FLAC, or Apple Lossless file. Absolutely none whatsoever.

The other take-away from this is that it is not really necessary to allocate a particularly large amount of system RAM to the audio buffer. We used to think that by pre-loading the whole track into memory it would sound better than if it was loaded chunk by chunk into a pair of wash-and-wear buffers. The additional CPU cycles involved in loading and switching ought to be degrading the sound. Over time, though, it has not turned out that way. We find that setting a larger audio buffer size seems to imbue the system with no audible improvements that we can reliably observe. I have for some time now left the audio buffer size on my reference system set to either 256MB or 512MB, and it seems to sound just fine to me. Tim does the same - and he listens on Stax SR009s.

All this is good news, because OS/X Mavericks seems to appreciate having lots of system RAM to play with.