5

I have a collection of music in .wav format, and would like to convert it to .aac/.mp4 using neroAacEnc.

How do I do this? I am using Arch Linux x86_64 and Xterm.

drs
  • 5,453
OMGtechy
  • 165

3 Answers3

5

Here is a quick one-liner that you can type in a terminal:

find . -name "*.wav" -print0 | while read -d $'\0' file; do neroAacEnc -2pass -q 1 -if "$file" -of "${file%wav}m4a"; done

You can also use ffmpeg, as @slm suggests,

find . -name "*.wav" -print0 | while read -d $'\0' file; do ffmpeg -i "$file" -c:a libfdk_aac -vbr 3 output.m4a "${file%wav}m4a"; done

I'm not sure how neroAacEnc compares to ffmpeg, but I know ffmpeg is advanced quite popular with many Linux users.


Explanation

find is a program that returns paths to files that match a certain file property, in this case the file's name. If all you wanted to know was what .wav files are in subdirectories of your current path, you would do find . -name "*.wav". Normally this outputs each file on a new line. The -print0 makes it separate the matches with a null character instead. This allows for proper handling of filenames with spaces when we pass the output to the next commands.

The | character is known as a pipe. It tells the shell to take the output of the command on the left and pass it as the input to the command on the right, in this case, the read command within the while loop.

The read command is used to take the output of find and assign it to a variable, "file". Normally this would assign values to "file" each word at a time, but the -d $'\0'$ causes the assignments to be delimited by the null character (matching how we delimited the files in find by using the -print0 flag).

The while loops causes read to iteratively assign values to "file" for each matching filename. The do and done are part of the standard bash syntax for a while loop:

while <something is true>; do
    <run some commands>
done

In this case, our "run some command" is either ffmpeg or neroAacEnc. In each of the cases, the input file (i.e., $file) is specified with the "file" variable that we assigned with read, and the output file (i.e., ${file%wav}w4a) is a manipulation of this variable that allows us to specify a different name for the output. Normally $file or ${file} would evaluate to the name of the file, say some song.wav. The % says to cut off from the right of the variable any sequence matching the characters[1] to the right of the % (i.e., "wav"). So ${file%wav} would evaluate to some song., and then the "m4a" is there to be the new end of the filename: some song.m4a.


[1] I say "characters" here for simplicity. The sequence to the right of the % could be a regular expression. For example, if we said ${file%w*v} and the variable was some song.w1234v, it would also evaluate to some song..

drs
  • 5,453
  • I tried this, but I get a lot of errors. It seems that the file name is getting split up into separate inputs (the filename has spaces in it). How can I fix this? – OMGtechy Apr 21 '13 at 20:47
  • Right, I forgot to add quotes around $file to handle spaces in file names. I've updated the commands, try again. – drs Apr 21 '13 at 20:55
  • I had to omit -2pass (it turns out it only works with a certain set of other settings, but omitting that this works great. Thank you! If you could explain why/what is going on here that would be even better, but if you don't have time I appreciate it regardless. – OMGtechy Apr 21 '13 at 21:21
  • 2
    For the record, fdk_aac and neroAacEnc are both considered to be good AAC encoders, while all the other AAC encoders in ffmpeg are... not. Also, fdk_aac cannot be legally distributed with ffmpeg in binary form due to licensing issues, so to use it you would have to compile your own ffmpeg. – evilsoup Apr 22 '13 at 00:44
  • Thanks for the update :) Now have a much better understanding of the find command! – OMGtechy Apr 25 '13 at 18:52
  • ffmpeg replaced with avconv http://askubuntu.com/questions/432542/is-ffmpeg-missing-from-the-official-repositories-in-14-04 – phillipsk Jan 03 '16 at 04:30
2

Not sure about the command line switches to neroAacEnc but something like this:

% cd <dir where .wav files are>
% find . -type f -name '*.wav' -exec sh -c '
orgfile="$0"
newfile="$(echo "$0" | sed 's/.wav/.aac/')"
neroAacEnc $orgfile $newfile
' {} \;

Or you could use ffmpeg to do the conversion (untested):

% cd <dir where .wav files are>
% find . -type f -name '*.wav' -exec sh -c '
orgfile="$0"
newfile="$(echo "$0" | sed 's/.wav/.aac/')"
ffmpeg -i $orgfile -ab 256 $newfile
' {} \;

As a script (put the below into a file)

#!/bin/bash

# myscript.bash
cd <dir where .wav files are>

find . -type f -name '*.wav' -exec sh -c '
orgfile="$0"
newfile="$(echo "$0" | sed 's/.wav/.aac/')"

neroAacEnc -2pass -q 1 -if $orgfile -of $newfile
' {} \;

After making the file (myscript.bash) make it executable chmod +x myscript.bash, run it ./myscript.bash, and you're done.

References

-FFmpeg and AAC Encoding Guide

NOTE: There are additional "recipes" for converting .wav to .aac and getting different qualities, characteristics, etc.

drs
  • 5,453
slm
  • 369,824
  • It would be called like this: neroAacEnc -2pass -q 1 -if <input_file> -of <output_file> – OMGtechy Apr 21 '13 at 19:43
  • Also, is this a file (like an executable> or do I type all this in at once? I'm pretty new to linux in terms of knowledge. – OMGtechy Apr 21 '13 at 19:46
  • Thank you, I tried this but get an error: "No output file specified" – OMGtechy Apr 21 '13 at 20:53
  • Can you run the script you created like this: bash -x myscript.bash > debug.log 2>&1 and post the contents of debug.log to http://pastebin.com/ please. – slm Apr 21 '13 at 21:26
2

I'd also use ffmpeg. If you use libfaac, it only supports -aq and not -vbr or -ab:

for f in **/*.wav; do ffmpeg -i "$f" -c:a libfaac -aq 150 "${f%wav}m4a"; done

** requires bash 4.0 or higher and shopt -s globstar or zsh. You can show information about the result files with ffmpeg -i.

According to http://ffmpeg.org/trac/ffmpeg/wiki/AACEncodingGuide, the native encoder (which was used if I didn't specify -c:a) is lower quality than libfaac, which is lower quality than libfdk_aac. --enable-libfdk_aac --enable-nonfree (or brew install ffmpeg --with-fdk-aac) includes support for libfdk_aac.

If you have 4 CPUs, this runs up to 4 processes in parallel:

find . -name \*.wav | parallel ffmpeg -i {} -c:a libfdk_aac -vbr 4.5 {.}.m4a

-vbr 0 is lowest, -vbr 5 is highest.

Lri
  • 5,223
  • +1 for the parallel processing, I have a quad core with hyper threading so this saves a lot of time! – OMGtechy Apr 21 '13 at 23:27