Sunday, December 9, 2012

Converting M4A to MP3

As some of you might know, I now am running a few music streams.  I'll link to the specifics of them at the bottom of this post. One of the problems I've had is that most of my music is in M4A format, ripped/converted through iTunes over the years.  The stream is an MP3 stream, and the streaming software (icecast2 + ices0) requires that the input files not be in M4A format... preferrably MP3.

When I started up the first stream ("Dole Whip" -- Polynesian, Hawaiian, Disneyland Adventureland themed) much of the content I was using was M4A.  I ended up using iTunes to convert the content to MP3.  This became cumbersome to convert, copy out into proper folders without their m4a counterparts, then remove them from the library before iTunes Match decided to do something with it.

I decided that a better way was to just collect everything as M4A or MP3 files, then convert the M4A files over to MP3s through command line stuff.  The first pass at this, I used the following shell script, which worked well.  It requires "bash" (standard shell), "faad" (AAC/M4A decoder), "lame" (MP3 encoder), and "id3" (MP3 metadata tool).

#!/bin/bash
for i in *.m4a; do
        echo "Converting: ${i%.m4a}.mp3"
        faad -o - "$i" | lame - "${i%.m4a}.mp3"
done
This worked well, but I usually get pretty religious about ID3/track metadata being correct. The above has the result of completely stripping out the metadata, resulting in a "naked" MP3 file.

I did notice that running "faad -i track.m4a" will dump out the metadata in a predictable/parsable manner.  Here's an example from its output:

title: Caribbean Blue
artist: Enya
album: Shepherd Moons
genre: New Age
track: 2
totaltracks: 12
disc: 1
totaldiscs: 1
date: 1991
compilation:
tempo: 00000 BPM
tool: iTunes v6.0.1.3, QuickTime 7.0.3
So, I decided to spend a few minutes, and throw together a quick perl script to "do the right thing."  The basic process is:
  1. faad -i (songfile).m4a  --  store aside all of the metadata in a hash
  2. faad -o -i (songfile).m4a | lame -b 192 - (songfile).mp3  --  convert it to mp3
  3. id3 -..... (songfile).mp3  --  add the metadata in to the mp3 file
Pretty straightforward.  I then just wrap this in a shell script to do this for multiple files in a directory, or in a directory in a directory, and a bunch of M4As will be converted to MP3s with all of their clothing intact. 

#!/usr/bin/perl
#
# m4a-2-mp3
#
#       converts m4a files to mp3 files, retaining metadata
#       requires: faad, lame, id3, perl (duh)
#
#       Scott Lawrence 2012  yorgle@gmail.com
#

if ( $infile eq "" ) { printf "No file specified.\n"; exit; }
if ( !-e $infile ) { printf "%s: File doesn't exist.\n", $infile; exit; }

printf "Working on %s\n", $infile;
$info = `faad -i "$infile" 2>&1`;

@lines = split /\n/, $info;
foreach $line ( @lines )
{
        chomp $line;
        $line =~ s/\n\r//g;
        if( -1 != index $line, ":" )
        {
                printf "%s\n", $line;
                ($key, $value) = split /:/, $line;
 
                # zot whitespace at beginning and end
                $value =~ s/^\s+//g;
                $value =~ s/\s+$//g;
                $key =~ s/\s+$//g;
                $key =~ s/^\s+//g;
 
                #shove it into our hash
                $id3{ $key } = $value;
        }
}
 
printf "Track is \"%s\" by \"%s\"\n", $id3{ "title" }, $id3{ "artist" }; 
$mp3file = $infile;
$mp3file =~ s/\.[mM]4[aA]/.mp3/g;
printf "Converting to MP3 file: %s\n", $mp3file;
 
$cmd = "faad -o - \"$infile\" | lame -b 192 - \"$mp3file\"";
`$cmd`;
 
printf "Adding back in tags\n";
$cmd = sprintf "id3 -t \"%s\" -T \"%s\" -a \"%s\" -A \"%s\" -y \"%s\" -g \"%s\" \"%s\"",
        $id3{ "title" }, $id3{ "track" },
        $id3{ "artist" }, $id3{ "album" },
        $id3{ "date" }, $id3{ "genre" }, $mp3file;
`$cmd`;

And as promised, here's the links of music streams I've got going currently:




No comments:

Post a Comment