By on December 27, 2014 under

From the start, I've had some trouble managing my music collection between Apple's ecosystem and Google's ecosystem. The initial version of Google's Music Manager (used to upload songs from iTunes to Google Play Music) did not support ALAC, though it did support FLAC. However, save for some plugins that often have issues, iTunes doesn't support FLAC.

The easiest solution at the time seemed to be converting all my FLAC media to ALAC, hosting it on iTunes, and hoping one day Google Music Manager would support ALAC. And it did, some time later.

However, a niggle. Google Music Manager only supports 16-bit depth ALAC, not 24-bit. This seems to be a rather arbitrary limitation, as ALAC only supports two bit depths of 16-bit and 24-bit, but I suppose one should be grateful ALAC is supported at all. It may also be some licensing limitation, or a cross-platform compatibility issue with the encoders available on Windows and OS X.

A few of my tracks (including the excellent FTL soundtrack by Ben Prunty) were provided as 24-bit FLAC and thus transparently converted by every converter I had handy (Max on OSX and dbPowerAmp on Windows) to 24-bit ALAC with no option to downconvert.

I thought I might use afconvert, OSX's built-in audio conversion binary that leverages CoreAudio. However, it was not clear as to how to force 16-bit depth vs 24-bit depth for ALAC.

Thanks to this obscure posting on Apple's mailing lists, there is an undocumented (as far as I could find) encoder flag for ALAC that forces 16-bit depth, which is exactly what I needed.

There are a few commands that are useful to know. afinfo will let you know if your file has 24 or 16-bit depth, in a command similar to this:

afinfo Ben\ Prunty\ Music\ -\ FTL\ -\ 02\ MilkyWay\ \(Explore\).m4a

And this would give you output like:

----
File:           afinfo
Fail: AudioFileOpenURL failed
File:           Ben Prunty Music - FTL - 02 MilkyWay (Explore).m4a
File type ID:   m4af
Num Tracks:     1
----
Data format:     2 ch,  44100 Hz, 'alac' (0x00000001) from 16-bit source, 4096 frames/packet
Channel layout: Stereo (L R)
estimated duration: 160.370363 sec
audio bytes: 13984607
audio packets: 1727
bit rate: 697471 bits per second
packet size upper bound: 10333
maximum packet size: 10333
audio data file offset: 12288
optimized
audio 7072333 valid frames + 0 priming + 1459 remainder = 7073792
source bit depth: I16
----

The final line source bit depth: I16 Indicates this file has an integer source bit depth of 16 (as opposed to floating-point, which I don't believe the ALAC format supports, though others may). If it were 24-bit, it would look like source bit depth: I24.

Using afconvert, you can convert the file this way:

afconvert -d alac/1 song.m4a song.m4a

This will read your file (in this example song.m4a) and overwrite it with an ALAC-encoded file with 16-bit source depth (you can, of course, change the second instance of song.m4a to song_16.m4a and not overwrite your original file). The /1 encoder flag is what triggers this. While I did find one piece of documentation that refers to the availability of encoder flags, but not what flags it accepts. It's likely mentioned somewhere in CoreAudio's docs, or possibly in the header files elsewhere in CoreAudio.

Combine this command with find and you can convert all the files in your current subdirectory recursively.

find ./ -name *.m4a -exec afconvert -d alac/1 {} {} \;

Be careful though with this, as it will do this conversion for all .m4a files, regardless of their bit depth. Also, it will do so serially, which is a bit of a waste. Two options:

  1. Pipe the output of find to something like parallel (GNU Parallel, which you'll likely have to add to your OSX machine via Homebrew or MacPorts). This will kick off an encoder per CPU core on your machine, which should make the process much faster. I've not tested this, but it should look something like: find ./ -name *.m4a | parallel afconvert -d alac/1 {} {}.
  2. Run a find ./ -name *.m4a -exec afinfo {} \; -exec echo {} \; and pipe the output of that command to grep, looking for the line "source bit depth: I24" with the flag -A 2 (lines after the match grep finds to print out along with the result). This should give you lines that contain the source bit depth, the line with dashes that follows, and the echo of the filename that we wrote out in the -exec part of find. Pipe to grep again, looking for lines with m4a, and you should get a nice list of all the files with 24-bit depth. Pipe that to xargs or parallel which will execute afconvert on each line of output. Something that (vaguely) should look like this (again, this is untested!) find ./ *.m4a -exec afinfo {} \; -exec echo {} \; | grep -A 2 "source bit depth: I24" | grep m4a | parallel afconvert -d alac/1 {} {}. It seems really complicated but take the command apart at every pipe from right to left and you can see what each part is doing.