I currently work for a music company, and one thing we need to do on the regs is take high-res files (think WAV, AIFF) and encode an mp3 version, for every song. This process was, until recently, handled by a third-party service called Zencoder. While this worked fairly well for us, when there were errors, we had little control (or information) on what went wrong. So we decided to do away with that dependency and figure out a way to encode our files within our own app so we have more flexibility and control. Here’s what we did:

First, I removed all traces of Zencoder from our app. Not only does it always feel great to remove some legacy code, as a bonus, this saved us over $4,000 per year in costs to Zencoder.

After playing around with some different approaches, we landed on using the free, open-source (and well-maintained) software AvConv and integrated it into our Ruby-based application. This is a fork off of ffmpeg, which we started with but had issues getting it to play nicely with Heroku. I’d try ffmpeg first though, the commands are the same, and it has even more support. Here, I’ll show you the snippet of code that does the heavy lifting for us, then I’ll break it down.

While this method looks like it just returns a string…. wait.. are those back ticks? Yes, that is one way to execute a system command with Ruby code. You can also use Kernel’s ‘system’ method:

system(“avconv -y -i #{input_filepath} -vn -qscale:a 4 -map_metadata -1 #{output_filepath}”)

… either will do.

The first command in this method, as you can see, is avconv. In order for that to execute anything, you need avconv installed! This could easily be done with Homebrew.

brew install libav

Alright, after the avconv command you’ll see -y. This will overwrite output files without asking (no, “are you sure you want to do this?” prompt).

-i is for the input filepath (high res file, like WAV or AIFF), so put that path right after the -i. Note that the filepath needs to be the full path, including the filename, (ex: /Users/yourname/desktop/hey_moon.wav).

-vn is to disable any video recording.

-qscale:a 4 handles the audio quality, and says ‘set it to 4 in the scale of 0 to 9

-map_metadata -1 clears any metadata from the input file so it doesn’t write to the output file (we want to start with a clean slate with metadata)

And finally, let your last argument be your output filepath (where the mp3 will go), and again, a full path, with a name and extension (ex: /Users/yourname/desktop/hey_moon.mp3)

You can easily try this by just running the command from your terminal (no back ticks when running via bash, save those for Ruby). Play around with it and watch it encode high-res files to mp3’s. You just need a WAV or AIFF file to play with and you’re good to go.

Ok, I’ll show you now the full class that handles our encoding process. For us, it lives at app/services/encode_mp3_service.rb: