/**
* Xtreme Media Player a cross-platform media player.
* Copyright (C) 2005-2011 Besmir Beqiri
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package xtrememp.tag;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.audio.mp3.MP3AudioHeader;
import org.jaudiotagger.audio.mp3.MP3File;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.TagException;
import org.tritonus.share.sampled.file.TAudioFileFormat;
import xtrememp.util.Utilities;
/**
* This class gives information (audio format and comments) about MPEG input or URL.
*
* @author Besmir Beqiri
*/
public class MpegInfo extends TagInfo {
protected String encoder = null;
protected String version = null;
protected String layer = null;
protected String emphasis = null;
protected String vendor = null;
protected boolean copyright = false;
protected boolean crc = false;
protected boolean original = false;
protected boolean privat = false;
protected boolean vbr = false;
/**
* Load and parse MP3 info from a file.
*
* @param file
* @throws IOException
* @throws UnsupportedAudioFileException
*/
@Override
public void load(File file) throws IOException, UnsupportedAudioFileException {
size = file.length();
location = file.getPath();
try {
MP3File mp3File = (MP3File) AudioFileIO.read(file);
MP3AudioHeader audioHeader = mp3File.getMP3AudioHeader();
Tag mpegTag = mp3File.getTag();
if (audioHeader != null) {
encodingType = audioHeader.getEncodingType();
encoder = audioHeader.getEncoder();
channels = audioHeader.getChannels();
switch (channels) {
case "Stereo":
channelsAsNumber = 2;
break;
case "Joint Stereo":
channelsAsNumber = 2;
break;
case "Dual":
channelsAsNumber = 2;
break;
case "Mono":
channelsAsNumber = 1;
break;
default:
channelsAsNumber = 0;
break;
}
sampleRateAsNumber = audioHeader.getSampleRateAsNumber();
bitRateAsNumber = (int) audioHeader.getBitRateAsNumber();
layer = audioHeader.getMpegLayer();
version = audioHeader.getMpegVersion();
crc = audioHeader.isProtected();
vbr = audioHeader.isVariableBitRate();
copyright = audioHeader.isCopyrighted();
original = audioHeader.isOriginal();
privat = audioHeader.isPrivate();
emphasis = audioHeader.getEmphasis();
duration = audioHeader.getTrackLength();
}
if (mpegTag != null) {
title = mpegTag.getFirst(FieldKey.TITLE);
artist = mpegTag.getFirst(FieldKey.ARTIST);
album = mpegTag.getFirst(FieldKey.ALBUM);
year = mpegTag.getFirst(FieldKey.YEAR);
genre = mpegTag.getFirst(FieldKey.GENRE);
track = mpegTag.getFirst(FieldKey.TRACK);
comment = mpegTag.getFirst(FieldKey.COMMENT);
artwork = mpegTag.getFirstArtwork();
}
} catch (CannotReadException ex) {
throw new IOException(ex);
} catch (TagException ex) {
throw new UnsupportedAudioFileException("Not MP3 audio format");
} catch (ReadOnlyFileException ex) {
throw new IOException(ex);
} catch (InvalidAudioFrameException ex) {
throw new UnsupportedAudioFileException("Not MP3 audio format");
}
}
/**
* Load and parse MPEG info from an URL.
*
* @param input
* @throws IOException
* @throws UnsupportedAudioFileException
*/
@Override
public void load(URL input) throws IOException, UnsupportedAudioFileException {
location = input.toString();
AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
loadInfo(aff);
loadShoutastInfo(aff);
}
/**
* Load and parse MPEG info from an input stream.
*
* @param input
* @throws IOException
* @throws UnsupportedAudioFileException
*/
@Override
public void load(InputStream input) throws IOException, UnsupportedAudioFileException {
AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
loadInfo(aff);
}
/**
* Load info from AudioFileFormat.
*
* @param aff the audio file format
*/
protected void loadInfo(AudioFileFormat aff) throws UnsupportedAudioFileException {
encodingType = aff.getType().toString();
if (!encodingType.equalsIgnoreCase("mp3")) {
throw new UnsupportedAudioFileException("Not MP3 audio format");
}
if (aff instanceof TAudioFileFormat) {
Map props = ((TAudioFileFormat) aff).properties();
if (props.containsKey("mp3.channels")) {
channelsAsNumber = ((Integer) props.get("mp3.channels")).intValue();
}
if (props.containsKey("mp3.frequency.hz")) {
sampleRateAsNumber = ((Integer) props.get("mp3.frequency.hz")).intValue();
}
if (props.containsKey("mp3.bitrate.nominal.bps")) {
bitRateAsNumber = ((Integer) props.get("mp3.bitrate.nominal.bps")).intValue() / 1000;
}
if (props.containsKey("mp3.version.layer")) {
layer = "Layer " + props.get("mp3.version.layer");
}
if (props.containsKey("mp3.version.mpeg")) {
version = (String) props.get("mp3.version.mpeg");
if (version.equals("1")) {
version = "MPEG1";
} else if (version.equals("2")) {
version = "MPEG2-LSF";
} else if (version.equals("2.5")) {
version = "MPEG2.5-LSF";
}
}
if (props.containsKey("mp3.mode")) {
int mode = ((Integer) props.get("mp3.mode")).intValue();
if (mode == 0) {
channels = "Stereo";
} else if (mode == 1) {
channels = "Joint Stereo";
} else if (mode == 2) {
channels = "Dual Channel";
} else if (mode == 3) {
channels = "Single Channel";
}
}
if (props.containsKey("mp3.crc")) {
crc = ((Boolean) props.get("mp3.crc")).booleanValue();
}
if (props.containsKey("mp3.vbr")) {
vbr = ((Boolean) props.get("mp3.vbr")).booleanValue();
}
if (props.containsKey("mp3.copyright")) {
copyright = ((Boolean) props.get("mp3.copyright")).booleanValue();
}
if (props.containsKey("mp3.original")) {
original = ((Boolean) props.get("mp3.original")).booleanValue();
}
if (props.containsKey("duration")) {
duration = Math.round((((Long) props.get("duration")).longValue()) / 1000000);
}
emphasis = "none";
if (props.containsKey("title")) {
title = (String) props.get("title");
}
if (props.containsKey("author")) {
artist = (String) props.get("author");
}
if (props.containsKey("album")) {
album = (String) props.get("album");
}
if (props.containsKey("date")) {
year = (String) props.get("date");
}
if (props.containsKey("mp3.id3tag.genre")) {
genre = (String) props.get("mp3.id3tag.genre");
}
if (props.containsKey("mp3.id3tag.track")) {
track = (String) props.get("mp3.id3tag.track");
}
}
}
/**
* Load Shoutcast info from AudioFileFormat.
*
* @param aff
* @throws IOException
* @throws UnsupportedAudioFileException
*/
protected void loadShoutastInfo(AudioFileFormat aff) throws IOException, UnsupportedAudioFileException {
encodingType = aff.getType().toString();
if (!encodingType.equalsIgnoreCase("mp3")) {
throw new UnsupportedAudioFileException("Not MP3 audio format");
}
if (aff instanceof TAudioFileFormat) {
Map props = ((TAudioFileFormat) aff).properties();
// Try shoutcast meta data (if any).
Iterator it = props.keySet().iterator();
comment = "";
while (it.hasNext()) {
String key = (String) it.next();
if (key.startsWith("mp3.shoutcast.metadata.")) {
String value = (String) props.get(key);
key = key.substring(23, key.length());
if (key.equalsIgnoreCase("icy-name")) {
title = value;
} else if (key.equalsIgnoreCase("icy-genre")) {
genre = value;
} else {
comment.concat(key + "=" + value);
}
}
}
}
}
public String getEncoder() {
return encoder;
}
public String getMpegLayer() {
return layer;
}
public String getMpegVersion() {
return version;
}
public boolean isVariableBitRate() {
return vbr;
}
public boolean isProtected() {
return crc;
}
public boolean isOriginal() {
return original;
}
public boolean isCopyrighted() {
return copyright;
}
public boolean isPrivate() {
return privat;
}
public String getEmphasis() {
return emphasis;
}
public long getSize() {
return size;
}
public String getLocation() {
return location;
}
@Override
public String getCodecDetails() {
StringBuilder sb = new StringBuilder();
sb.append("<html><b>Encoding type: </b>");
sb.append(getEncodingType().toUpperCase());
if (!Utilities.isNullOrEmpty(getEncoder())) {
sb.append("<br><b>Encoder: </b>");
sb.append(getEncoder());
}
sb.append("<br><b>Version: </b>");
sb.append(getMpegVersion());
sb.append("<br><b>Layer: </b>");
sb.append(getMpegLayer());
sb.append("<br><b>Sampling rate: </b>");
sb.append(getSampleRateAsNumber()).append(" Hz");
sb.append("<br><b>Bitrate: </b>");
sb.append(getBitRateAsNumber()).append(" Kbps");
sb.append("<br><b>Channels: </b>");
sb.append(getChannelsAsNumber());
sb.append("<br><b>Channels mode: </b>");
sb.append(getChannels());
sb.append("<br><b>CRC: </b>");
sb.append(isProtected());
sb.append("<br><b>Variable Bitrate: </b>");
sb.append(isVariableBitRate());
sb.append("<br><b>Copyrighted: </b>");
sb.append(isCopyrighted());
sb.append("<br><b>Private: </b>");
sb.append(isPrivate());
sb.append("<br><b>Emphasis: </b>");
sb.append(getEmphasis());
if (size > 0) {
sb.append("<br><b>Size: </b>");
sb.append(Utilities.byteCountToDisplaySize(size));
}
sb.append("</html>");
return sb.toString();
}
}