Both ALAC and FLAC are lossless audio formats and files will usually have more or less the same size when converted from one format to the other. I use ffmpeg -i track.flac track.m4a to convert between these two formats but I notice that the resulting ALAC files are much smaller than the original ones. When using a converter software like the MediaHuman Audio Converter, the size of the ALACs will remain around the same size as the FLACs so I guess I'm missing some flags here that are causing ffmpeg to downsample the signal.

  • ffmpeg generally needs the -acodec for any destination to be sure you get the conversation done right. There are lots of front ends that use ffmpeg but I've noticed many do not include ALAC as an output option. Aug 21 '18 at 18:07

Ok, I was probably a little quick to ask here but for the sake of future reference here is the answer:

One should pass the flag -acodec alac to ffmpeg for a lossless conversion between FLAC and ALAC:

ffmpeg -i track.flac -acodec alac track.m4a

  • 8
    To explain what's happening here: .m4a is an Apple variant of the MP4 file format. FFmpeg and most other s/w will default to the AAC encoder when outputting to mp4 or m4a, hence the express -acodec option is needed.
    – Gyan
    Jan 8 '18 at 7:15
  • 4
    Some FLAC files contain an album cover thumbnail. You can add -vcodec copy to include those in your new ALAC files.
    – Sean
    Nov 20 '19 at 1:31

And for converting a whole directory...


pushd './Music/Some Album [flac]'
bash flac-to-alac.sh 


#!/usr/bin/env bash
my_bin="$(dirname $0)/flac-to-alac-ffmpeg.sh"
find . -type f -name '*.flac' -exec "$my_bin" {} \;


#!/usr/bin/env bash
set -e # fail if there's any error
set -u

my_new="$(echo $(dirname "$my_file")/$(basename "$my_file" .flac).m4a)"
echo "$my_file"
ffmpeg -y -v 0 -i "$my_file" -acodec alac "$my_new"
# only gets here if the conversion didn't fail
#rm "$my_file"


I thought I could get this to work in a single command, but it doesn't escape special characters, such as [.

It seemed so promising...

#!/usr/bin/env bash
set -e # exit immediately on error
set -u # error if a variable is misspelled

while read -r my_file; do
  # ./foo/bar.flac => ./foo/bar.m4a
  my_new="$(dirname "$my_file")/$(basename "$my_file" .flac).m4a"

  ffmpeg -i "$my_file" -acodec alac "$my_new"

  # safe because of set -e, but still do a test run
  #rm "$my_file"
done <<< "$(find . -type f -name '*.flac')"
  • 4
    Here's a one-liner I use for conversion: for i in *.flac; do echo $i; ffmpeg -i "$i" -y -v 0 -vcodec copy -acodec alac "${i%.flac}".m4a && rm -f "$i"; done Mar 13 '20 at 7:52
  • @PaulLindner That looks like a perfect option for single directories, no recursion.
    – coolaj86
    Mar 13 '20 at 17:29
  • I did this (borrowing from @PaulLindner, whose solution didn't quite work on my system): for i in *.flac; do echo $i; ffmpeg -i "$i" -y -acodec alac "${i%.flac}".m4a; done
    – minisaurus
    Feb 10 at 20:56

Not the answer you're looking for? Browse other questions tagged or ask your own question.