I have an Nissan Altima with a BOSE radio that allows me to hook up an USB thumbdrive containing mp3 files. The problem is most of my audiobooks are in m4b format. Previously I’ve used tools like mp3splt and tried to split on ‘silence’ or timed increments (say 15 min) but I was getting mp3 files that would be split in midsentence and sometimes midword. It became very annoying after awhile.
So, I came up with a really simple script to convert an audiobook (m4b) into mp3 files splitting on the chapters. We are dependent on FFmpeg::Command and a modified FFprobe Perl module.
In the following example, we are converting a Ben Bova audiobook but we are going to specify to start the track numbering at “10″ because the 2nd file ended with track “9″.
jason@jason-Inspiron-1545 ~/bin $ ./test_mp4_info.pl -i "/home/jason/Audiobooks/Ben Bova/Mars/Mars 3.m4b" -o mp3 -a "Mars" -t 10
Converting "Mars 3.m4b" to "mp3/010 Mars.mp3"... album: Mars artist: Ben Bova title: 010 - Mars genre: Audiobook track: 10 ... COMPLETE Converting "Mars 3.m4b" to "mp3/011 Mars.mp3"... album: Mars artist: Ben Bova title: 011 - Mars genre: Audiobook track: 11 ... COMPLETE Converting "Mars 3.m4b" to "mp3/012 Mars.mp3"... album: Mars artist: Ben Bova title: 012 - Mars genre: Audiobook track: 12 ... COMPLETE Converting "Mars 3.m4b" to "mp3/013 Mars.mp3"... album: Mars artist: Ben Bova title: 013 - Mars genre: Audiobook track: 13 ... COMPLETE Converting "Mars 3.m4b" to "mp3/014 Mars.mp3"... album: Mars artist: Ben Bova title: 014 - Mars genre: Audiobook track: 14 ... COMPLETE
Source code:
#!/usr/bin/perl
use strict;
use warnings;
use lib qw(/home/jason/bin);
use Getopt::Std;
use File::Basename;
use FFmpeg::Command;
use FFprobe;
$|++;
###############################
sub _encode_mp3 {
my ($input_file, $output_dir, $album, $starting_track) = @_;
my %tags = ();
my $track_number;
my $mp4 = FFprobe->probe_file($input_file);
my $base_output_file = basename($input_file);
$base_output_file =~ s/\.\w+$//;
if (exists $mp4->{format}->{'TAG:comment'}) {
$tags{genre} = $mp4->{format}->{'TAG:comment'};
$tags{genre} =~ s/("')//g;
}
if (exists $mp4->{format}->{'TAG:genre'}) {
$tags{genre} = $mp4->{format}->{'TAG:genre'};
$tags{genre} =~ s/("')//g;
}
if (exists $mp4->{format}->{'TAG:artist'}) {
$tags{artist} = $mp4->{format}->{'TAG:artist'};
$tags{artist} =~ s/("')//g;
}
if ($album) {
$tags{album} = $album;
} elsif (exists $mp4->{format}->{'TAG:album'}) {
$tags{album} = $mp4->{format}->{'TAG:album'};
}
$tags{album} =~ s/("')//g;
$track_number = $starting_track if $starting_track;
foreach my $chapter (sort keys %{$mp4->{chapters}}) {
unless ($starting_track) {
$track_number = $chapter;
}
my $output_file = sprintf "%s/%03d %s.mp3", $output_dir, $track_number, $tags{album};
my $start = $mp4->{chapters}->{$chapter}->{start};
my $duration = $mp4->{chapters}->{$chapter}->{end} - $start;
my @options = ();
if ($album) {
$tags{title} = sprintf "%03d - %s", $track_number, $album;
} else {
if (exists $mp4->{format}->{'TAG:title'}) {
$tags{title} = sprintf "%03d - %s", $track_number, $mp4->{format}->{'TAG:title'};
} else {
$tags{title} = sprintf "%03d - %s", $track_number, $base_output_file;
}
}
$tags{title} =~ s/("')//g;
my $ffmpeg = FFmpeg::Command->new;
$ffmpeg->input_options({
file => $input_file,
});
$ffmpeg->output_options({
'file' => $output_file,
'audio_codec' => 'libmp3lame',
'audio_bit_rate' => 64,
});
printf "Converting \"%s\" to \"%s\"...\n", basename($input_file), $output_file;

I have other, general comments, but one about the MP3s in particular that’s proven very difficult for me as a Primary teacher: differentiating between the “with words” and “without words” versions. I have a filter in place on my download program, which keeps me from downloading “with words” files into my “without words” folder (I think it went something like /2/1/301.mp3 = hymnal, with words, page 301, while 2/2/301.mp3 = hymnal, without words, page 301.) Having “w” (or something) appended to the track number would be… nifty.
Do you have these files somewhere we can download?
Thanks for article. I was not aware of such utility on linux as well.
Thanks much for that.