I needed to generate a bunch of audio clips. After seeing how tedious this would be with a GUI audio editor, I did some digging to find a faster solution that I could run as a batch from the command line. Turns out it was quite easy.
I first turned to the excellent
FFmpeg library. I knew I would be able to read and convert between a wide variety of formats (from mp3 to aac and Apple Lossless) and specify start and stop points. I was surprised to learn that it lacked the functionality to add fades.
For the fading, I turned to
SoX, which has the ability to add audio filters, but as far as I can tell can’t read as many formats out of the box.
Installation is simple with
$ brew install ffmpeg $ brew install sox
After everything is installed, the commands are straightforward.
$ ffmpeg -y -i orig.m4a -ss 0:02:30 one.aiff
orig.m4a to the lossless
one.aiff file. The
-y option will automatically overwrite the output if it exists and the
-ss option specifies the start time which (in this example) will trim the first two and a half minutes from
$ sox one.aiff two.aiff fade 2 0:01:00 5
This trims the
one.aiff down to 1 minute in length, adds a two second fade to the beginning, adds a five second fade to the end, and saves the result as
$ ffmpeg -y -i two.aiff -ab 128k clip.mp3
Finally, we use ffmpeg agin to transcode
two.aiff down to our final 128k mp3 clip. The
-ab flag is used to set the audio bitrate.
This works fine and all, but a better solution is to pipe the results of one command to the next to avoid creating the intermediate files:
$ ffmpeg -i orig.mp3 -ss 0:02:30 -f aiff pipe: | \ sox -t aiff - -t aiff - fade 2 1:00 5 | \ ffmpeg -y -i pipe: -ab 128k clip.mp3
There are a few things to note.
- To pipe the output from the first
ffmpegcommand, we need to specify the output format with
- We also need to specify the incoming and outgoing formats of the pipes in the
-t aiff -.
- I initially used
.wavas the intermediate format, but this didn’t work due to issues with the pipes and file headers.
- The backslash characters are just to break up the command into shorter lines.