5

I have some songs in wav format. I would like to convert them to flac (which is also lossless, but has compression).

The solution needs to recurse through subdirectories to find .wav or .WAV files (ideally case insensitive), convert them to .flac and output the .flac files to a different directory tree. The original wav files are in ~/Music and the output flac files could go into ~/Music_Flac.

I am using Arch Linux x86_64 and I have ffmpeg as follows:

ffmpeg version 3.4.2 Copyright (c) 2000-2018 the FFmpeg developers
built with gcc 7.3.0 (GCC)
configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-avisynth --enable-avresample --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libass --enable-libbluray --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-shared --enable-version3 --enable-omx
libavutil      55. 78.100 / 55. 78.100
libavcodec     57.107.100 / 57.107.100
libavformat    57. 83.100 / 57. 83.100
libavdevice    57. 10.100 / 57. 10.100
libavfilter     6.107.100 /  6.107.100
libavresample   3.  7.  0 /  3.  7.  0
libswscale      4.  8.100 /  4.  8.100
libswresample   2.  9.100 /  2.  9.100
libpostproc    54.  7.100 / 54.  7.100
MountainX
  • 17,168
  • 59
  • 155
  • 264
  • Do you need the same subdirectory structure under `~/Music_Flac` as under `~/Music`? – nohillside Mar 04 '18 at 08:53
  • @patrix yes, the same subdirectory structure under ~/Music_Flac. – MountainX Mar 04 '18 at 09:23
  • https://www.linux.com/learn/weekend-project-batch-convert-your-music-collection-linux is quite old but give you a lot of different possibilities : FUSE based GUI based Batch based – user4089 Mar 04 '18 at 09:48

4 Answers4

8

If you want to replace all wav reclusively with their flac counterparts, the easiest way I found is using flac binaries:

find . -name '*.wav' -exec flac --best {} --delete-input-file \;

Here's a breakdown of the different parts of the command:

  • find .: This command searches for files in the current directory and all subdirectories (indicated by the .).

  • -name '*.wav': This flag specifies that we are looking for files with a .wav extension. The * is a wildcard that matches any character or group of characters, so this flag will match any file that ends with .wav.

  • -exec: This flag tells the find command to execute a command on the files that match the search criteria.

  • flac --best {} --delete-input-file: This is the command that is executed on the matching files. The {} is a placeholder that represents the file that is being processed by the find command. The flac command converts the file to the FLAC format using the highest level of compression specified by the --best flag. The --delete-input-file flag tells the flac command to delete the original .wav file after it has been successfully converted to the FLAC format.

  • \;: This is required to signal the end of the flac command for the -exec option to function properly.

ofrancisco
  • 181
  • 1
  • 3
3

find + ffmpeg solution:

find ~/Music -type f -iname "*.wav" -exec sh -c \
'bn=${1##*/}; bn=${bn%.*}; ffmpeg -loglevel 16 -i "$1" "${0}${bn}.flac"' ~/Music_Flac/ {} \;
  • $0 - passed into shell command as a destination directory ~/Music_Flac/
  • $1 - passed into shell command as a filepath {}
  • bn=${1##*/} - file basename without directory path
  • bn=${bn%.*} - file basename with extension truncated
  • -loglevel 16 - set the logging level 16 used by ffmpeg
RomanPerekhrest
  • 29,703
  • 3
  • 43
  • 67
1

Another option would be to use bash's globbing to find the wav files, then shell parameter expansion features to change the directory structure and filenames:

shopt -s globstar nocaseglob
for input in Music/**/*.wav
do
  indir=$(dirname "$input")
  outdir=${indir/#Music/Music_Flac}
  [ ! -d "$outdir" ] && mkdir -p "$outdir"
  infile=$(basename "$input")
  outfile=${infile%.???}.flac
  echo ffmpeg -i "$input" "${outdir}/${outfile}"
done

If the files are only ever *.wav and *.WAV, you could skip the shopt nocaseglob and instead use for input in Music/**/*.wav Music/**/*.WAV.

I don't know what options you want to use for ffmpeg, but I provided an echo example of the input and output file paths that you can build from.

On this sample directory tree:

$ tree Music
Music
├── a.wav
├── b.WAV
├── c d.wav
└── subdir1
    ├── a.wav
    ├── b.WAV
    ├── c d.wav
    └── subdir2
        ├── a.wav
        ├── b.WAV
        └── c d.wav

the sample command output is:

ffmpeg -i Music/a.wav Music_Flac/a.flac
ffmpeg -i Music/b.WAV Music_Flac/b.flac
ffmpeg -i Music/c d.wav Music_Flac/c d.flac
ffmpeg -i Music/subdir1/a.wav Music_Flac/subdir1/a.flac
ffmpeg -i Music/subdir1/b.WAV Music_Flac/subdir1/b.flac
ffmpeg -i Music/subdir1/c d.wav Music_Flac/subdir1/c d.flac
ffmpeg -i Music/subdir1/subdir2/a.wav Music_Flac/subdir1/subdir2/a.flac
ffmpeg -i Music/subdir1/subdir2/b.WAV Music_Flac/subdir1/subdir2/b.flac
ffmpeg -i Music/subdir1/subdir2/c d.wav Music_Flac/subdir1/subdir2/c d.flac

... along with the required mkdir commands along the way.

Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
0

In addition to @RomanPerekhrest 's answer, which I selected as the correct answer to the question, there is a GUI solution which also works well:

GitHub - dfaust/soundkonverter: soundKonverter is in maintenance mode, PRs are welcome.

It is in the Arch repos too:

Arch Linux - soundkonverter 3.0.1-1 (x86_64)

MountainX
  • 17,168
  • 59
  • 155
  • 264
  • 1
    Not sure why this was down voted, but SoundKonverter actually works very well. I've been very impressed with it. – MountainX Apr 01 '18 at 00:34