/*
* MpegAudioFileReader.java
*
* This file is part of Tritonus: http://www.tritonus.org/
*/
/*
* Copyright (c) 1999 -2001 by Matthias Pfisterer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
|<--- this code is formatted to fit into 80 columns --->|
*/
package org.tritonus.sampled.file.mpeg;
import java.io.InputStream;
import java.io.IOException;
import java.io.EOFException;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.UnsupportedAudioFileException;
import org.tritonus.share.TDebug;
import org.tritonus.share.sampled.file.TAudioFileFormat;
import org.tritonus.share.sampled.file.TAudioFileReader;
/*
* @author Matthias Pfisterer
*/
public class MpegAudioFileReader
extends TAudioFileReader
{
private static final int SYNC = 0xFFE00000;
private static final AudioFormat.Encoding[][] sm_aEncodings =
{
{new AudioFormat.Encoding("MPEG2DOT5L3"),
new AudioFormat.Encoding("MPEG2DOT5L2"),
new AudioFormat.Encoding("MPEG2DOT5L1")},
{null,
null,
null}, /* reserved */
{new AudioFormat.Encoding("MPEG2L3"),
new AudioFormat.Encoding("MPEG2L2"),
new AudioFormat.Encoding("MPEG2L1")},
{new AudioFormat.Encoding("MPEG1L3"),
new AudioFormat.Encoding("MPEG1L2"),
new AudioFormat.Encoding("MPEG1L1")},
};
private static final float[][] sm_afSamplingRates =
{
{11025.0F, 12000.0F, 8000.0F},
{0.0F, 0.0F, 0.0F}, /* reserved */
{22050.0F, 24000.0F, 16000.0F},
{44100.0F, 48000.0F, 32000.0F},
};
private static final int MARK_LIMIT = 4;
public MpegAudioFileReader()
{
super(MARK_LIMIT, true);
}
@Override
protected AudioFileFormat getAudioFileFormat(InputStream inputStream, long lFileSizeInBytes)
throws UnsupportedAudioFileException, IOException
{
if (TDebug.TraceAudioFileReader) { TDebug.out("MpegAudioFileReader.getAudioFileFormat(): begin"); }
int b0 = inputStream.read();
int b1 = inputStream.read();
int b2 = inputStream.read();
int b3 = inputStream.read();
if ((b0 | b1 | b2 | b3) < 0)
{
throw new EOFException();
}
int nHeader = (b0 << 24) + (b1 << 16) + (b2 << 8) + (b3 << 0);
/*
* We check for the sync bits. If they are present, we
* assume that we have an MPEG bitstream.
*/
if ((nHeader & SYNC) != SYNC)
{
throw new UnsupportedAudioFileException("not a MPEG stream: no sync bits");
}
int nVersion = (nHeader >> 19) & 0x3;
if (nVersion == 1)
{
throw new UnsupportedAudioFileException("not a MPEG stream: wrong version");
}
int nLayer = (nHeader >> 17) & 0x3;
if (nLayer == 0)
{
throw new UnsupportedAudioFileException("not a MPEG stream: wrong layer");
}
AudioFormat.Encoding encoding = sm_aEncodings[nVersion][nLayer - 1];
// TODO: bit rate, protection
int nSFIndex = (nHeader >> 10) & 0x3;
if (nSFIndex == 3)
{
throw new UnsupportedAudioFileException("not a MPEG stream: wrong sampling rate");
}
float fSamplingRate = sm_afSamplingRates[nVersion][nSFIndex];
int nMode = (nHeader >> 6) & 0x3;
int nChannels = nMode == 3 ? 1 : 2;
AudioFormat format = new AudioFormat(
encoding,
fSamplingRate,
AudioSystem.NOT_SPECIFIED /*???*/,
nChannels,
AudioSystem.NOT_SPECIFIED /*????*/,
AudioSystem.NOT_SPECIFIED /*????*/,
true);
//$$fb 2000-08-15: workaround for the fixed extension problem in AudioFileFormat.Type
// see org.tritonus.share.sampled.AudioFileTypes.java
AudioFileFormat.Type type = new AudioFileFormat.Type("MPEG", "mpeg");
if (encoding.equals(new AudioFormat.Encoding("MPEG1L3")))
{
type = new AudioFileFormat.Type("MP3", "mp3");
}
/*
If the file size is known, we derive the number of frames
('frame size') from it.
If the values don't fit into integers, we leave them at
NOT_SPECIFIED. 'Unknown' is considered less incorrect than
a wrong value.
*/
// [fb] not specifying it causes Sun's Wave file writer to write rubbish
int nByteSize = AudioSystem.NOT_SPECIFIED;
int nFrameSize = AudioSystem.NOT_SPECIFIED;
if (lFileSizeInBytes != AudioSystem.NOT_SPECIFIED
&& lFileSizeInBytes <= Integer.MAX_VALUE)
{
nByteSize = (int) lFileSizeInBytes;
// TODO: check if we can calculate a useful value here
// nFrameSize = (int) (lFileSizeInBytes / 33);
}
AudioFileFormat audioFileFormat =
new TAudioFileFormat(
type,
format,
nFrameSize,
nByteSize);
if (TDebug.TraceAudioFileReader) { TDebug.out("MpegAudioFileReader.getAudioFileFormat(): end"); }
return audioFileFormat;
}
}
/*** MpegAudioFileReader.java ***/