/*
Written by Greg Taylor
Part of Design and Implementation of a TCP/IP Network-Based Embedded MP3 Player
Senior Project at California Polytechnic State University, San Luis Obispo
Spring 2004
*/
import java.io.*;
public class MP3File extends File {
public MP3File(String pathname) throws NullPointerException {
super(pathname);
mTag = new ID3v1();
}
public MP3File(String parent, String pathname) throws NullPointerException {
super(parent, pathname);
mTag = new ID3v1();
}
public MP3File(File fileName) throws NullPointerException {
this(fileName.getAbsolutePath());
}
/*
* This method should be called before any of the other accessor methods
* because if an MP3 does not have a tag, calling other accessor methods
* will return null strings, but not cause an error otherwise.
*/
public boolean hasTag() throws IOException {
readTag();
return mHasTag;
}
public String getTitle() throws IOException {
readTag();
return mTag.getTitle();
}
public String getArtist() throws IOException {
readTag();
return mTag.getArtist();
}
public String getAlbum() throws IOException {
readTag();
return mTag.getAlbum();
}
public String getYear() throws IOException {
readTag();
return mTag.getYear();
}
public String getComment() throws IOException {
readTag();
return mTag.getComment();
}
public int getAlbumTrack() throws IOException {
readTag();
return mTag.getAlbumTrack();
}
public String getGenre() throws IOException {
readTag();
return mTag.getGenre();
}
public int getBitrate() throws IOException {
if (!mReadBitrate) {
calcBitrate();
mReadBitrate = true;
}
return mBitrate;
}
public boolean isVBR() {return mIsVBR;}
private void readTag() throws IOException {
if (!mReadTag) {
mHasTag = mTag.readTag(this);
mReadTag = true;
}
}
private void calcBitrate() throws IOException {
long totalBitrate = 0, bitrate, bytesRead;
int numFrames = 0;
int currByte;
int frameHeader = 0xFA;
int nibbleAfterBitrate = 0;
BufferedInputStream in =
new BufferedInputStream(new FileInputStream(this));
String XingVBRHeader = "Xing"; // Xing VBR header contains this
String FhGVBRHeader = "VBRI"; // Fraunhofer VBR header contains this
byte buf[] = new byte[XingVBRHeader.length()];
boolean foundCBRBitrate = false;
// Look for VBR Header to indicate whether MP3 is VBR
for (bytesRead = 0; bytesRead < VBR_HEADER_DEPTH; bytesRead++) {
// shift bytes into buf from left
System.arraycopy(buf, 1, buf, 0, buf.length - 1);
buf[buf.length - 1] = (byte) in.read();
if (new String(buf, ID3v1.ENC_TYPE).substring(0,
XingVBRHeader.length()).equals(XingVBRHeader)) {
mIsVBR = true;
break;
}
else if (new String(buf, ID3v1.ENC_TYPE).substring(0,
FhGVBRHeader.length()).equals(FhGVBRHeader)) {
mIsVBR = true;
break;
}
}
// reset to beginning of file
in = new BufferedInputStream(new FileInputStream(this));
if (!mIsVBR) {
// mBitrate gets bitrate from first valid frame header
currByte = in.read();
while (currByte != -1 && !foundCBRBitrate) {
// first byte of frame header
if (currByte == 0xFF) {
currByte = in.read();
// second byte of frame header
if (currByte != -1 && (currByte & frameHeader) == frameHeader) {
mBitrate = readBitrate(in);
if (mBitrate != -1) {
foundCBRBitrate = true;
}
}
}
currByte = in.read();
}
}
else {
// mBitrate gets bitrate averaged over all valid frame headers
currByte = in.read();
while (currByte != -1) {
// first byte of frame header
if (currByte == 0xFF) {
currByte = in.read();
// second byte of frame header
if (numFrames == 0 && (currByte & frameHeader) == frameHeader) {
// mark this position in file so we can compare nibble after
// bitrate
in.mark(1);
bitrate = readBitrate(in);
if (bitrate != -1) {
// save the form of this header so we only search for this
// type of header
frameHeader = currByte;
in.reset();
nibbleAfterBitrate = in.read() & 0x0F;
totalBitrate += bitrate;
numFrames++;
}
}
if (currByte == frameHeader) {
// mark this position in file so we can compare nibble after
// bitrate
in.mark(1);
bitrate = readBitrate(in);
in.reset();
if (bitrate != -1 && ((in.read() & 0x0F) ==
nibbleAfterBitrate)) {
totalBitrate += bitrate;
numFrames++;
}
}
}
currByte = in.read();
}
if (numFrames > 0) {
mBitrate = (int) totalBitrate/numFrames;
}
else {
mBitrate = 0;
}
}
in.close();
}
private int readBitrate(InputStream in) throws IOException {
int info = in.read();
int bitrate;
if (info == -1) {
return -1;
}
switch (info & 0xF0) { // only look at most significant nibble
case 0x10:
bitrate = 32;
break;
case 0x20:
bitrate = 40;
break;
case 0x30:
bitrate = 48;
break;
case 0x40:
bitrate = 56;
break;
case 0x50:
bitrate = 64;
break;
case 0x60:
bitrate = 80;
break;
case 0x70:
bitrate = 96;
break;
case 0x80:
bitrate = 112;
break;
case 0x90:
bitrate = 128;
break;
case 0xA0:
bitrate = 160;
break;
case 0xB0:
bitrate = 192;
break;
case 0xC0:
bitrate = 224;
break;
case 0xD0:
bitrate = 256;
break;
case 0xE0:
bitrate = 320;
break;
default: // invalid or free bitrate
bitrate = -1;
break;
}
return bitrate;
}
private ID3tag mTag;
private int mBitrate;
private boolean mHasTag;
private boolean mReadTag;
private boolean mReadBitrate;
private boolean mIsVBR;
// how far into file to look for VBR header
private static final int VBR_HEADER_DEPTH = 4096;
}
edit: codebox instead of code