Converting MP3s in Java

I was surprised to find that there was very little information on the internets on decoding MP3s for manipulation in Java, which is one of the things I would like to add to my project. After spending almost two weeks on this problem, I have finally cobbled together a solution, that while not perfect, gets close to a resolution. I would like to share my findings in the interest of helping any other struggling souls out there who are stuck. At this point, the main problem I am having is that certain large files are not being played in their entirety – only snippets are being played. I feel this is probably occurring somewhere in the logic of my array assignment; perhaps another pair of eyes could can spot something and post a tip in comments.

In any event, in order to get started, one needs a decoder class. There are two APIs that provide such classes, JLayer and Tritonus, which offers a plugin that can work with Java Sound. I used JLayer with MP3SPI as they have some documentation that serves as a good starting point.

Here is some code that exemplifies the process. This method takes a file name string in as a parameter and after defining an output format it is read through the decoder object and the resultant bytes are assigned to a ByteArrayOutputStream. After this, I send the stream as a byte array on return for further manipulation.

public byte[] testPlay(String filename) throws UnsupportedAudioFileException, IOException {
ByteArrayOutputStream f = new ByteArrayOutputStream();
File file = new File(filename);
AudioInputStream in = AudioSystem.getAudioInputStream(file);
AudioFormat baseFormat = in.getFormat();
AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
    baseFormat.getSampleRate(), 16,
    baseFormat.getChannels(), baseFormat.getChannels() * 2,
    baseFormat.getSampleRate(), true);
DecodedMpegAudioInputStream decoder = new DecodedMpegAudioInputStream(decodedFormat, in);
try {
    byte[] byteData = new byte[4];
    int nBytesRead = 0;
    int offset = 0;
    while (nBytesRead != -1) {
        nBytesRead = decoder.read(byteData, offset, byteData.length);
        if (nBytesRead != -1) {
            int numShorts = nBytesRead >> 1;
            for (int j = 0; j < numShorts; j++) {
                f.write(byteData[j]);
            }
        }
    }
} catch (SynthException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}
byte[] buffer = new byte[f.size()];
buffer = f.toByteArray();
f.close();
return buffer;
}

The above method is called like so and I proceed to assign the byte array as a short array so that I can feed it into the format that synthesis API I use, JSyn, prefers.


stream = (InputStream) (new FileInputStream(fileName));
String ext = fileName.substring(fileName.lastIndexOf('.')+1, fileName.length());
if (ext.equalsIgnoreCase("mp3") ) {
    byte[] buffer = testPlay(fileName);
    int j=0;
    short shrtData[] = new short[buffer.length];
    for (int i = 0; i < buffer.length ; i++) {
        int sampled = ((int)(buffer[i])) & 0x00FF;
        sampled += ((int)(buffer[i++])) << 8;
        shrtData[j++] = (short) sampled;
}
if( shrtData != null ){
    sampleTable.allocate( shrtData.length );
    sampleTable.write( shrtData );
}
Hope this is helpful to someone out there…

Bookmark the permalink.