30

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.

Paghillect
  • 917
  • 1
  • 7
  • 14
  • `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. – Hardcore Games Aug 21 '18 at 18:07

2 Answers2

44

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

Paghillect
  • 917
  • 1
  • 7
  • 14
  • 9
    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 08 '18 at 07:15
  • 5
    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 01:31
3

And for converting a whole directory...

Usage

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

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" {} \;

flac-to-alac-ffmpeg.sh:

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

my_file=$1
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"

Alternative:

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')"
coolaj86
  • 455
  • 4
  • 8
  • 8
    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` – Paul Lindner Mar 13 '20 at 07: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 '21 at 20:56
  • 1
    audio files have the gnarliest filenames ever. I had `10cc` and `10CC` conflicting on a big job recently. im using clementine and audiobrainz to sanitise it all. – Tomachi Oct 11 '21 at 13:34
  • I do NOT recommend deleting in the same command after encoding, do it manually to be sure, here is my version of the one-liner: `for i in *.flac; do ffmpeg -i "$i" -y -vn -c:a alac "${i%.flac}".m4a; done` – Rodrigo Polo May 18 '22 at 10:08