These are a couple of m-files I wrote to read and write mp3 audio files (i.e. files compressed using MPEG-Audio layer 3 encoding) under Matlab.
The mp3read script started out little, but has now become somewhat larger. Rather than actually decoding the mp3 stream, it cheats by calling an external mp3 decoder program to convert the file to wav, then reading in that temporary file. But it does do some tricks like only decompressing the part of the file that is required rather than the whole thing; this can be useful for accessing very large mp3 files.
The syntax of mp3read() attempts to duplicate wavread() as closely as possible, including trying to duplicate the OPTS.fmt fields and the 'size' syntax etc. Because mpg123 supports on-the-fly downsampling by 2 or 4, and conversion to mono, these are supported as options beyond the first two arguments.
Here is the function: mp3read.m
Note that it won't work unless you also have the mpg123 and mp3info binaries; see "External Commands" below.
Here are some examples of use:
In mid-2006 I noticed that mp3read followed by mp3write followed by mp3read effectively delayed the waveform by 2257 samples (at 44 kHz). So I introduced code to discard the first 2257 samples to ensure that the waveforms remained time aligned. As best I could understand, mpg123 (v 0.5.9) was including the "warm-up" samples from the synthesis filterbank which are more properly discarded.
Then in late 2009 I noticed that some chord recognition code, which used mp3read to read files which were then segmented on the basis of some hand-marked timings, suddenly started getting much poorer results. It turned out that I had upgraded my version of mpg123 to v 1.9.0, and the warm-up samples had been fixed in this version. So my code was discarding 2257 *good* samples, and the data was skewed 51ms early relative to the hand labels.
Hence, the current version of mp3read distributed here does not discard any samples by default -- appropriate for the recent versions of mpg123 pointed to here. But if you know you're running an old, v 0.5.9, mpg123, you should edit the mp3read.m source to set the flag MPG123059 = 1.
Note also that the 'size' function relies on the number of blocks reported by mp3info. However, many mp3 files include additional information about the size of the file in the so-called Xing header, embedded in the first frame, which can specify that a certain number of samples from start and end should additionally be dropped. mp3info doesn't read that, and there's no way for my code to probe it except by running mpg123. Hence, the results of mp3read(fn,'size') may sometimes overestimate the length of the actual vector you'll get if you read the whole file.
An mp3write/mp3read loop still adds samples on to the *end* every time (in order to round the data out to an even number of blocks). If you want to keep your data the same length, you should truncate when you read back, e.g.
>> mp3write(d,sr,'tmp.mp3'); >> d1 = mp3read('tmp.mp3',length(d));
You can control the pre-delay-chopping by specifying 0 (or however many samples you want to discard) as a 5th argument to mp3read.
Although it's called mp3read, it will, in fact, read any MPEG Audio file recognized by the underlying Unix utilities (i.e. MPEG-1 Audio layers 1, 2, and 3). It does not recognize MPEG-4 audio files (*.m4a etc.) but you can convert these to mp3 with mplayer and lame e.g.
mplayer file.m4a -ao pcm:file=file.wav lame -h -b 128 file.wav file.mp3 rm file.wav
Since mp3read seemed useful, I decided to write a complementary mp3write. This uses the same dodge of calling an external program (lame) to do the actual encoding. Under Unix, it actually uses my popen mex extension to write it a bit at a time; if popen is not available (e.g. Windows), it just writes a temporary uncompressed wav file, then executes the lame compressor on that.
Here is the function: mp3write.m Note that it won't work unless you also have the lame binary; see "External Commands" below. It will also work without using a large temporary file if you can install the popenw mex extension.
Usage is analogous to wavwrite i.e. mp3write(data, srate, filename[, opts]). If opts is specified, it gives extra command line options for lame (e.g. to control the compressed bitrate). The default opts are "--quiet -h".
The functions actually use some freely-available Unix utilities. As such, they work principally on Unix versions of Matlab (e.g. Linux and Mac OS X). However, these utilities have been ported to Windows, so you should be able to get them to work there also (more details at the bottom of the page).
Specifically, for mp3read you need the mpg123 decoder (note: mpg321 is not an adequate substitute, because it lacks certain options), and the mp3info scanner. You can find them here:
As mentioned above, the mp3read Matlab function depends on two external programs, mpg123 and mp3info, which were originally developed for Linux. To make the script work on a Windows system, you need versions of these programs that work on that architecture, which we provide here for your convenience:
To make them work, you also need to make small changes to the mp3read.m and mp3write.m scripts. First, you must change the location that the script looks for binaries e.g. change the lines:
%%%%%% Location of the binaries mpg123 = '/usr/bin/mpg123'; % for mp3read mp3info = '/usr/bin/mp3info'; % for mp3read lame = '/usr/bin/lame'; % for mp3write
to point to the directory where you put the binaries above, e.g.
mpg123 = 'C:\Matlab6p5\work\project\mpg123.exe'; mp3info = 'C:\Matlab6p5\work\project\mp3info.exe'; lame = 'C:\Matlab6p5\work\project\lame.exe';
Secondly, you must also change the directory where temporary files are written, and the command used to delete them, e.g.:
%%%%%% Directory for temporary file (if needed) tmpdir = '/tmp/'; %%%%%% Command to delete temporary file (if needed) rmcmd = 'rm';
.. to be a suitable directory for temporary files on your system and the appropriate command to delete them, e.g.
tmpdir = 'C:\Matlab6p5\work\project\tmp\'; % don't forget trailing slash rmcmd = 'del';
Thanks to Keansub Lee and Meredith Morris for their help.