8 min read

The codec nobody rewrote

SACD rips come compressed with DST, and for twenty years nobody wrote a decoder you could freely ship. What that gap looked like, how 1-bit closed it, and what the app does with those files now.

Updated

The goal

Super Audio CD was Sony and Philips’ attempt, in 1999, to replace the CD with something that sounded better. It stores music differently: one bit at a time, 2.8 million times a second, a format called DSD. The disc never displaced the CD, but a few thousand titles were released on it, classical and jazz above all. The people who bought them have since ripped them to files, the way everyone ripped their CDs.

The catch is what is inside those files. To fit a long album on a disc, the audio was usually compressed with something called DST. It is lossless, in the strict sense: decoding it gives back exactly the bits that went in. A rip lands on your disk either as one .dff file per track or as an .iso image of the whole disc. Either way the audio inside is still compressed. Most players cannot open it. The workaround has been to run everything through a desktop converter first, which produces a second copy at twice the size and leaves you managing two libraries.

I wanted 1-bit to open those files as they are. Tap a track, hear it. No converter, no second copy, and no change to the one promise the app is built on: the bits reaching your DAC are the bits in the file.

What already exists

The first thing to do with any codec is find out whether someone has already implemented it. GitHub, crates.io, pkg.go.dev, SourceForge. Every open DST decoder I could find traces back to one of two ancestors. One is FFmpeg’s, which is LGPL. The other is the ISO reference code from 2004, which anyone can download from ISO’s own server and which carries a Philips copyright notice and an MPEG conformance grant. The one candidate labelled Apache-2.0 reproduces that Philips notice in its own file headers, which tells you what it actually is.

A format this old usually has several independent implementations by now, and at least one you can drop into a commercial product without reading anything first. DST has none. Twenty years of people wanting it, and everyone took the same code. A couple of paid players on the App Store do play it, and their decoders can only have come from one of those two places.

The reason nobody rewrote it was patents, and here the situation is simpler than the folklore suggests. Rather than assemble a list myself, I went to the one Philips published: its own patents essential to SACD, last revised in March 2009 and now only on archive.org. Nothing on it was filed after December 1999, which the twenty-year rule clears by the end of 2019. Philips’ current licensing catalogue has no SACD programme in it at all. None of that is advice to anybody else, but it was enough for me, for a decoder I ship myself, after reading the primary documents. The caution that kept everyone away was correct when they formed it, and had quietly stopped being correct about six years before I went looking.

The gap

For an iOS app, none of what exists is a drop-in, and the reasons differ for each.

FFmpeg’s decoder is LGPL, and LGPL on iOS is contested ground. VLC was pulled from the App Store in 2011 after a copyright holder complained, and only returned in 2013 once VideoLAN had relicensed its engine. The contested piece is the clause giving users the right to relink a modified library, which practitioners have argued since 2013 cannot really be satisfied on a signed iOS binary. Plenty of apps ship LGPL FFmpeg anyway and nothing has happened to them. It is still a whole framework and a compliance surface for one decoder I did not otherwise want.

The ISO reference code has a cleaner licence. It is not open source in the usual sense. It is a copyright grant scoped to products that conform to the standard, and it explicitly covers modifications, which is what a port is. No copyleft. Nothing that argues with the App Store. The gap there is the code itself. Written in 2004 for 32-bit machines, it had never been hardened against hostile input and, as it turned out, could not run at all on a modern computer.

The third option is to write a decoder from the prose specification, having never seen anybody else’s. That is the expensive route, and the only one you can lose by accident. You lose it by reading. Open the ISO zip and the clean-room option is gone for whoever opened it.

There was an engineering gap on top of the licensing one. A DST decoder is real arithmetic, not a file-format shim, and nobody had published what it costs on a phone. And whatever route I took, the decoder could not sit in the audio path. 1-bit has a set of regression tests pinning bit-exact output across every container and every gapless transition. Putting new code in that path means proving all of it again, and being wrong about it silently.

What I did

Measurement came first, arranged so it would not close any door. FFmpeg’s dstdec.c was compiled, unmodified, into a throwaway benchmark harness, and never read. The answer it gave was 14.3 times realtime on a single core of an iPhone 13 for stereo DSD64, which puts a sixty-minute album at around four minutes of one core. Comfortable. The ISO package stayed undownloaded until the licensing decision was made, in that order deliberately, and the decision went to the ISO code.

The package arrives as a reference encoder, a reference decoder, plain gcc makefiles, and a small test matrix of DSD clips with shell scripts that encode, decode and compare. The encoder builds with one include-path shim and works fine. The decoder segfaults. Not on awkward input, on everything, including the kit’s own files. It dies at exactly 0x100000000, which is a number that gives away the cause before you open the debugger: a 32-bit quantity used as a pointer. The culprit is a two-dimensional array allocator striding by the wrong size, written in 2004 for a world where that was the same size.

The golden reference the port was supposed to prove itself against did not exist.

What replaced it was stronger. The kit ships the clips in pairs, an uncompressed original and its compressed twin, and decoding the twin back to the original byte for byte is precisely what conformance means. No reference decoder required. The encoder still works, so the missing rate and channel combinations could be manufactured on the spot. The port was fixed for 64-bit, given bounds checks the original never had, and put through a fuzz sweep of thirty thousand mutated inputs under the address and undefined-behaviour sanitisers. Nine pairs out of nine came back bit-exact, across three sample rates and three channel counts.

One thing fell out of that which I enjoyed more than I should have. FFmpeg’s canonical DST sample is the ISO kit’s own Test1 clip, compressed by a different build of the same encoder. Its test suite has used that file for years. Decoding it produces the kit’s original payload exactly. It has had external provenance all along and nobody wrote it down.

Then the architecture, which mattered more than the port. The decoder never went near the audio path. It decodes the file into an ordinary uncompressed .dff in the cache, and the existing playback path opens that file knowing nothing about DST. A decoded DST file and a file that was never compressed are the same file. The bit-exact tests still pass, and they pass structurally rather than because a new decoder happened not to break anything.

A DST file is decoded into a plain uncompressed file in the cache, and the existing playback path plays that file. Nothing below the decoder changed. DST-compressed .dffDecoderPlain uncompressed .dffExisting playback pathDAC NOTHING BELOW CHANGED
The decoder produces a file, not a stream. Everything under the dashed line predates DST and did not learn about it.

Something nice fell out of that for free. The decoder writes its output from front to back. The reader that plays files already knows how to read a file that is still growing, because that is what playing a download looks like. A decoder is a downloader with a known exact length and no network to stall on. Playback releases once eight seconds of audio are on disk and the reader chases the decode head the rest of the way, which on a phone it never catches. The work in that was the cancellation path, not the streaming.

What 1-bit does now

A DST-compressed .dff in your library shows up as what it is: DSD64 or DSD128, with its real duration, rather than as an unknown audio file with no length. Tap it and it plays. If the file is on a server it downloads first. Decoding then starts, and sound begins about a second later. The status line reads “Decoding” with a percentage while the rest of the track catches up in the background. The next track in an album is decoded ahead during the current one. An SACD plays gaplessly, the way the disc did.

The decoded copy goes into the same reclaimable cache the app uses for streamed music. It counts against that cache’s budget, it is evicted least-recently-played when space runs short, and it never touches anything you downloaded deliberately. The second play of a track is instant. If the copy has been evicted, it is simply decoded again, from a local file in seconds and with no network at all.

An SACD .iso image opens too. The disc’s track list appears as ordinary rows, with the disc’s own track names, that play, download and sit in playlists like anything else. The audio inside them goes through the same decoder.

Two limits, stated plainly. Stereo only, and DSD64 or DSD128 only. Multichannel DST and DSD256 are not decoded yet. Real SACD rips are overwhelmingly stereo DSD64, which is what shipped, and I have yet to be sent one of the others.

The licence notice sits verbatim at the top of every ported file and in the app’s acknowledgments, as the grant requires. It has a typo. It reads ISO/EIC where it means ISO/IEC, and has since 2004. It is reproduced exactly as written, with a test that fails if anyone ever helpfully corrects it.

Related posts

Comments