Browse Source

Tools feexered

git-svn-id: http://repo.nplusc.de/svn/iZink@111 8b19561d-0d00-6744-8ac1-9afc8f58a8aa
masterX244 11 years ago
parent
commit
833dd630cd
52 changed files with 4061 additions and 16 deletions
  1. BIN
      ToolKit/libs/Mp3Utils/jl1.0.1.jar
  2. BIN
      ToolKit/libs/Mp3Utils/mp3spi1.9.5.jar
  3. 2 0
      ToolKit/libs/Mp3Utils/src/META-INF/services/javax.sound.sampled.spi.AudioFileReader
  4. 2 0
      ToolKit/libs/Mp3Utils/src/META-INF/services/javax.sound.sampled.spi.FormatConversionProvider
  5. 31 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/PropertiesContainer.java
  6. 335 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/convert/DecodedMpegAudioInputStream.java
  7. 120 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/convert/MpegFormatConversionProvider.java
  8. 131 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/IcyListener.java
  9. 106 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/MpegAudioFileFormat.java
  10. 830 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/MpegAudioFileReader.java
  11. 67 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/MpegAudioFormat.java
  12. 47 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/MpegEncoding.java
  13. 40 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/MpegFileFormatType.java
  14. 423 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/IcyInputStream.java
  15. 42 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/IcyTag.java
  16. 50 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/MP3MetadataParser.java
  17. 52 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/MP3Tag.java
  18. 62 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/MP3TagParseSupport.java
  19. 36 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/StringableTag.java
  20. 44 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/TagParseEvent.java
  21. 37 0
      ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/TagParseListener.java
  22. BIN
      ToolKit/libs/Mp3Utils/tritonus_share.jar
  23. BIN
      ToolKit/libs/OggUtils/jogg-0.0.7.jar
  24. BIN
      ToolKit/libs/OggUtils/jorbis-0.0.15.jar
  25. 2 0
      ToolKit/libs/OggUtils/src/META-INF/services/javax.sound.sampled.spi.AudioFileReader
  26. 2 0
      ToolKit/libs/OggUtils/src/META-INF/services/javax.sound.sampled.spi.FormatConversionProvider
  27. 31 0
      ToolKit/libs/OggUtils/src/javazoom/spi/PropertiesContainer.java
  28. 519 0
      ToolKit/libs/OggUtils/src/javazoom/spi/vorbis/sampled/convert/DecodedVorbisAudioInputStream.java
  29. 244 0
      ToolKit/libs/OggUtils/src/javazoom/spi/vorbis/sampled/convert/VorbisFormatConversionProvider.java
  30. 85 0
      ToolKit/libs/OggUtils/src/javazoom/spi/vorbis/sampled/file/VorbisAudioFileFormat.java
  31. 508 0
      ToolKit/libs/OggUtils/src/javazoom/spi/vorbis/sampled/file/VorbisAudioFileReader.java
  32. 66 0
      ToolKit/libs/OggUtils/src/javazoom/spi/vorbis/sampled/file/VorbisAudioFormat.java
  33. 41 0
      ToolKit/libs/OggUtils/src/javazoom/spi/vorbis/sampled/file/VorbisEncoding.java
  34. 41 0
      ToolKit/libs/OggUtils/src/javazoom/spi/vorbis/sampled/file/VorbisFileFormatType.java
  35. BIN
      ToolKit/libs/OggUtils/vorbisspi1.0.3.jar
  36. BIN
      ToolKit/libs/aspectJ/aspectj-1.7.3-src.jar
  37. BIN
      ToolKit/libs/aspectJ/aspectj-1.7.3.jar
  38. BIN
      ToolKit/libs/aspectJ/aspectjrt.jar
  39. BIN
      ToolKit/libs/aspectJ/aspectjrt1.7.3-src.jar
  40. BIN
      ToolKit/libs/aspectJ/aspectjtools.jar
  41. BIN
      ToolKit/libs/aspectJ/aspectjtools1.7.3-src.jar
  42. BIN
      ToolKit/libs/aspectJ/aspectjweaver.jar
  43. BIN
      ToolKit/libs/aspectJ/aspectjweaver1.7.3-src.jar
  44. BIN
      ToolKit/libs/aspectJ/org.aspectj.matcher-1.7.3-src.jar
  45. BIN
      ToolKit/libs/aspectJ/org.aspectj.matcher.jar
  46. BIN
      ToolKit/libs/m4a-TK/jaad-0.8.4-src.zip
  47. BIN
      ToolKit/libs/m4a-TK/jaad-0.8.4.jar
  48. BIN
      ToolKit/libs/mp4rawparse/isoparser-1.0-RC-1-javadoc.jar
  49. BIN
      ToolKit/libs/mp4rawparse/isoparser-1.0-RC-1-sources.jar
  50. BIN
      ToolKit/libs/mp4rawparse/isoparser-1.0-RC-1.jar
  51. 37 0
      ToolKit/libs/nblibraries.properties
  52. 28 16
      ToolKit/src/de/nplusc/izc/tools/baseTools/Tools.java

BIN
ToolKit/libs/Mp3Utils/jl1.0.1.jar


BIN
ToolKit/libs/Mp3Utils/mp3spi1.9.5.jar


+ 2 - 0
ToolKit/libs/Mp3Utils/src/META-INF/services/javax.sound.sampled.spi.AudioFileReader

@@ -0,0 +1,2 @@
+#  for the javalayer mp3 decoder
+javazoom.spi.mpeg.sampled.file.MpegAudioFileReader

+ 2 - 0
ToolKit/libs/Mp3Utils/src/META-INF/services/javax.sound.sampled.spi.FormatConversionProvider

@@ -0,0 +1,2 @@
+# for the javalayer mp3 decoder
+javazoom.spi.mpeg.sampled.convert.MpegFormatConversionProvider

+ 31 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/PropertiesContainer.java

@@ -0,0 +1,31 @@
+/*
+ * PropertiesContainer.
+ * 
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ * 
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+
+package javazoom.spi;
+
+import java.util.Map;
+
+public interface PropertiesContainer
+{
+	public Map properties();
+}

+ 335 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/convert/DecodedMpegAudioInputStream.java

@@ -0,0 +1,335 @@
+/*
+ *   DecodedMpegAudioInputStream.
+ * 
+ *   JavaZOOM : mp3spi@javazoom.net 
+ * 				http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------------
+ *   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.
+ *------------------------------------------------------------------------
+ */
+
+package javazoom.spi.mpeg.sampled.convert;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+
+import javazoom.jl.decoder.Bitstream;
+import javazoom.jl.decoder.BitstreamException;
+import javazoom.jl.decoder.Decoder;
+import javazoom.jl.decoder.DecoderException;
+import javazoom.jl.decoder.Equalizer;
+import javazoom.jl.decoder.Header;
+import javazoom.jl.decoder.Obuffer;
+import javazoom.spi.PropertiesContainer;
+import javazoom.spi.mpeg.sampled.file.IcyListener;
+import javazoom.spi.mpeg.sampled.file.tag.TagParseEvent;
+import javazoom.spi.mpeg.sampled.file.tag.TagParseListener;
+
+import org.tritonus.share.TDebug;
+import org.tritonus.share.sampled.convert.TAsynchronousFilteredAudioInputStream;
+
+/**
+ * Main decoder.
+ */
+public class DecodedMpegAudioInputStream extends TAsynchronousFilteredAudioInputStream implements PropertiesContainer, TagParseListener
+{
+	private InputStream m_encodedStream;
+	private Bitstream m_bitstream;
+	private Decoder m_decoder;
+	private Equalizer m_equalizer;
+	private float[] m_equalizer_values;
+	private Header m_header;
+	private DMAISObuffer m_oBuffer;
+
+	// Bytes info.
+	private long byteslength = -1;
+	private long currentByte = 0;	
+	// Frame info.
+	private int frameslength = -1;
+	private long currentFrame = 0;
+	private int currentFramesize = 0;
+	private int currentBitrate = -1;
+	// Time info.
+	private long currentMicrosecond = 0;
+	// Shoutcast stream info
+	private IcyListener shoutlst = null;
+	
+
+	private HashMap properties = null;
+
+	public DecodedMpegAudioInputStream(AudioFormat outputFormat, AudioInputStream inputStream)
+	{
+		super(outputFormat, -1);
+		if (TDebug.TraceAudioConverter) 
+		{
+			TDebug.out(">DecodedMpegAudioInputStream(AudioFormat outputFormat, AudioInputStream inputStream)");
+		}
+		try
+		{
+			// Try to find out inputstream length to allow skip.
+			byteslength = inputStream.available();
+		}
+		catch (IOException e)
+		{
+			TDebug.out("DecodedMpegAudioInputStream : Cannot run inputStream.available() : "+e.getMessage());
+			byteslength = -1;
+		}		
+		m_encodedStream = inputStream;		
+		shoutlst = IcyListener.getInstance();
+		shoutlst.reset();
+		m_bitstream = new Bitstream(inputStream);
+		m_decoder = new Decoder(null);
+		m_equalizer = new Equalizer();
+		m_equalizer_values = new float[32];
+		for (int b=0;b<m_equalizer.getBandCount();b++)
+		{
+			m_equalizer_values[b] = m_equalizer.getBand(b);
+		}
+		m_decoder.setEqualizer(m_equalizer);
+		m_oBuffer = new DMAISObuffer(outputFormat.getChannels());
+		m_decoder.setOutputBuffer(m_oBuffer);
+		try
+		{
+			m_header = m_bitstream.readFrame();
+			if ((m_header != null) && (frameslength == -1) && (byteslength > 0))  frameslength = m_header.max_number_of_frames((int)byteslength);
+		}
+		catch (BitstreamException e)
+		{
+			TDebug.out("DecodedMpegAudioInputStream : Cannot read first frame : "+e.getMessage());
+			byteslength = -1;
+		}
+		properties = new HashMap();
+	}
+
+	/**
+	 * Return dynamic properties.
+	 * 
+	 * <ul>
+	 * <li><b>mp3.frame</b> [Long], current frame position.
+	 * <li><b>mp3.frame.bitrate</b> [Integer], bitrate of the current frame.
+	 * <li><b>mp3.frame.size.bytes</b> [Integer], size in bytes of the current frame.
+	 * <li><b>mp3.position.byte</b> [Long], current position in bytes in the stream.
+	 * <li><b>mp3.position.microseconds</b> [Long], elapsed microseconds.
+	 * <li><b>mp3.equalizer</b> float[32], interactive equalizer array, values could be in [-1.0, +1.0].
+	 * <li><b>mp3.shoutcast.metadata.key</b> [String], Shoutcast meta key with matching value.
+	 * <br>For instance : 
+	 * <br>mp3.shoutcast.metadata.StreamTitle=Current song playing in stream.
+	 * <br>mp3.shoutcast.metadata.StreamUrl=Url info.
+	 * </ul>
+	 */
+	public Map properties()
+	{
+		properties.put("mp3.frame",new Long(currentFrame));
+		properties.put("mp3.frame.bitrate",new Integer(currentBitrate));
+		properties.put("mp3.frame.size.bytes",new Integer(currentFramesize));
+		properties.put("mp3.position.byte",new Long(currentByte));
+		properties.put("mp3.position.microseconds",new Long(currentMicrosecond));
+		properties.put("mp3.equalizer",m_equalizer_values);
+		// Optionnal shoutcast stream meta-data.				
+		if (shoutlst != null)
+		{
+			String surl = shoutlst.getStreamUrl();
+			String stitle = shoutlst.getStreamTitle();
+			if ((stitle != null) && (stitle.trim().length()>0)) properties.put("mp3.shoutcast.metadata.StreamTitle",stitle);
+			if ((surl != null) && (surl.trim().length()>0)) properties.put("mp3.shoutcast.metadata.StreamUrl",surl);
+		}		
+		return properties;	 
+	}
+	
+	public void execute()
+	{
+		if (TDebug.TraceAudioConverter) TDebug.out("execute() : begin");
+		try
+		{
+			// Following line hangs when FrameSize is available in AudioFormat.			
+			Header header = null;
+			if (m_header == null) header = m_bitstream.readFrame();
+			else header = m_header;												
+			if (TDebug.TraceAudioConverter) TDebug.out("execute() : header = "+header);
+			if (header == null)
+			{
+				if (TDebug.TraceAudioConverter)
+				{
+					TDebug.out("header is null (end of mpeg stream)");
+				}
+				getCircularBuffer().close();				
+				return;
+			}			 
+			currentFrame++;
+			currentBitrate = header.bitrate_instant();
+			currentFramesize = header.calculate_framesize();
+			currentByte = currentByte + currentFramesize;
+			currentMicrosecond = (long) (currentFrame* header.ms_per_frame()*1000.0f);
+			for (int b=0;b<m_equalizer_values.length;b++)
+			{
+				m_equalizer.setBand(b,m_equalizer_values[b]);					
+			}			
+			m_decoder.setEqualizer(m_equalizer);
+			Obuffer decoderOutput = m_decoder.decodeFrame(header, m_bitstream);
+			m_bitstream.closeFrame();
+			getCircularBuffer().write(m_oBuffer.getBuffer(), 0, m_oBuffer.getCurrentBufferSize());
+			m_oBuffer.reset();
+			if (m_header != null) m_header = null;
+		}
+		catch (BitstreamException e)
+		{
+			if (TDebug.TraceAudioConverter)
+			{
+				TDebug.out(e);
+			}
+		}
+		catch (DecoderException e)
+		{
+			if (TDebug.TraceAudioConverter)
+			{
+				TDebug.out(e);
+			}
+		}
+		if (TDebug.TraceAudioConverter) TDebug.out("execute() : end");		
+	}
+
+	public long skip(long bytes)
+	{
+		if ((byteslength > 0) && (frameslength > 0))
+		{
+			float ratio = bytes*1.0f/byteslength*1.0f;
+			long bytesread = skipFrames((long) (ratio*frameslength));
+			currentByte = currentByte + bytesread;
+            m_header = null;
+			return bytesread;					
+		}
+		else return -1;
+	}
+	
+	/**
+	 * Skip frames.
+	 * You don't need to call it severals times, it will exactly skip given frames number.
+	 * @param frames
+	 * @return bytes length skipped matching to frames skipped.
+	 */
+	public long skipFrames(long frames)
+	{
+		if (TDebug.TraceAudioConverter) TDebug.out("skip(long frames) : begin");		
+		int framesRead = 0;
+		int bytesReads = 0;
+		try
+		{
+			for (int i=0;i<frames;i++)
+			{
+				Header header = m_bitstream.readFrame();
+				if (header != null)
+				{
+					int fsize = header.calculate_framesize();					
+					bytesReads = bytesReads + fsize;
+				} 
+				m_bitstream.closeFrame();
+				framesRead++;
+			} 
+		}
+		catch (BitstreamException e)
+		{
+			if (TDebug.TraceAudioConverter) TDebug.out(e);
+		}
+		if (TDebug.TraceAudioConverter) TDebug.out("skip(long frames) : end");
+		currentFrame = currentFrame + framesRead;
+		return bytesReads;
+	}
+	
+	private boolean isBigEndian()
+	{
+		return getFormat().isBigEndian();
+	}
+
+	public void close() throws IOException
+	{
+		super.close();
+		m_encodedStream.close();
+	}
+
+	private class DMAISObuffer extends Obuffer
+	{
+		private int m_nChannels;
+		private byte[] m_abBuffer;
+		private int[] m_anBufferPointers;
+		private boolean m_bIsBigEndian;
+		public DMAISObuffer(int nChannels)
+		{
+			m_nChannels = nChannels;
+			m_abBuffer = new byte[OBUFFERSIZE * nChannels];
+			m_anBufferPointers = new int[nChannels];
+			reset();
+			m_bIsBigEndian = DecodedMpegAudioInputStream.this.isBigEndian();
+		}
+		public void append(int nChannel, short sValue)
+		{
+			byte bFirstByte;
+			byte bSecondByte;
+			if (m_bIsBigEndian)
+			{
+				bFirstByte = (byte) ((sValue >>> 8) & 0xFF);
+				bSecondByte = (byte) (sValue & 0xFF);
+			}
+			else // little endian
+				{
+				bFirstByte = (byte) (sValue & 0xFF);
+				bSecondByte = (byte) ((sValue >>> 8) & 0xFF);
+			}
+			m_abBuffer[m_anBufferPointers[nChannel]] = bFirstByte;
+			m_abBuffer[m_anBufferPointers[nChannel] + 1] = bSecondByte;
+			m_anBufferPointers[nChannel] += m_nChannels * 2;
+		}
+		public void set_stop_flag()
+		{
+		}
+		public void close()
+		{
+		}
+		public void write_buffer(int nValue)
+		{
+		}
+		public void clear_buffer()
+		{
+		}
+		public byte[] getBuffer()
+		{
+			return m_abBuffer;
+		}
+		public int getCurrentBufferSize()
+		{
+			return m_anBufferPointers[0];
+		}
+		public void reset()
+		{
+			for (int i = 0; i < m_nChannels; i++)
+			{
+				/*	Points to byte location,
+				 *	implicitely assuming 16 bit
+				 *	samples.
+				 */
+				m_anBufferPointers[i] = i * 2;
+			}
+		}
+	}
+	
+	public void tagParsed(TagParseEvent tpe)
+	{
+		System.out.println("TAG:"+tpe.getTag());
+	}	
+}

+ 120 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/convert/MpegFormatConversionProvider.java

@@ -0,0 +1,120 @@
+/*
+ *   MpegFormatConversionProvider.
+ * 
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ * 
+ * --------------------------------------------------------------------------- 
+ *   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.
+ * --------------------------------------------------------------------------
+ */
+
+
+package	javazoom.spi.mpeg.sampled.convert;
+
+
+import java.util.Arrays;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+
+import javazoom.spi.mpeg.sampled.file.MpegEncoding;
+
+import org.tritonus.share.TDebug;
+import org.tritonus.share.sampled.Encodings;
+import org.tritonus.share.sampled.convert.TEncodingFormatConversionProvider;
+
+/**
+ * ConversionProvider for MPEG files.
+  */
+public class MpegFormatConversionProvider extends TEncodingFormatConversionProvider
+{
+	private static final AudioFormat.Encoding	MP3 = Encodings.getEncoding("MP3");
+	private static final AudioFormat.Encoding	PCM_SIGNED = Encodings.getEncoding("PCM_SIGNED");
+
+	private static final AudioFormat[]	INPUT_FORMATS =
+	{
+		// mono
+		new AudioFormat(MP3, -1.0F, -1, 1, -1, -1.0F, false),
+		new AudioFormat(MP3, -1.0F, -1, 1, -1, -1.0F, true),
+		// stereo
+		new AudioFormat(MP3, -1.0F, -1, 2, -1, -1.0F, false),
+		new AudioFormat(MP3, -1.0F, -1, 2, -1, -1.0F, true),
+	};
+
+
+	private static final AudioFormat[]	OUTPUT_FORMATS =
+	{
+		// mono, 16 bit signed
+		new AudioFormat(PCM_SIGNED, -1.0F, 16, 1, 2, -1.0F, false),
+		new AudioFormat(PCM_SIGNED, -1.0F, 16, 1, 2, -1.0F, true),
+		// stereo, 16 bit signed
+		new AudioFormat(PCM_SIGNED, -1.0F, 16, 2, 4, -1.0F, false),
+		new AudioFormat(PCM_SIGNED, -1.0F, 16, 2, 4, -1.0F, true),
+	};
+
+	/**	
+	 * Constructor.
+	 */
+	public MpegFormatConversionProvider()
+	{
+		super(Arrays.asList(INPUT_FORMATS), Arrays.asList(OUTPUT_FORMATS));
+		if (TDebug.TraceAudioConverter) 
+		{
+			TDebug.out(">MpegFormatConversionProvider()");
+		}
+	}
+
+	public AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream audioInputStream)
+	{
+		if (TDebug.TraceAudioConverter) 
+		{
+			TDebug.out(">MpegFormatConversionProvider.getAudioInputStream(AudioFormat targetFormat, AudioInputStream audioInputStream):");
+		}
+		return new DecodedMpegAudioInputStream(targetFormat, audioInputStream);
+	}
+
+	/**
+	 * Add conversion support for any MpegEncoding source with FrameRate or FrameSize not empty.
+	 * @param targetFormat
+	 * @param sourceFormat
+	 * @return
+	 */
+	public boolean isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat)
+	{
+		if (TDebug.TraceAudioConverter) 
+		{
+					TDebug.out(">MpegFormatConversionProvider.isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat):");
+					TDebug.out("checking if conversion possible");
+					TDebug.out("from: " + sourceFormat);
+					TDebug.out("to: " + targetFormat);
+		}
+
+		boolean conversion = super.isConversionSupported(targetFormat, sourceFormat);
+		if (conversion == false)
+		{
+			AudioFormat.Encoding enc = sourceFormat.getEncoding();
+			if (enc instanceof MpegEncoding)
+			{
+				if ((sourceFormat.getFrameRate() != AudioSystem.NOT_SPECIFIED) || (sourceFormat.getFrameSize() != AudioSystem.NOT_SPECIFIED))
+				{
+					conversion = true;
+				}
+			}
+		}
+		return conversion;
+	}
+}

+ 131 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/IcyListener.java

@@ -0,0 +1,131 @@
+/*
+ * IcyListener.
+ * 
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ * 
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+
+package javazoom.spi.mpeg.sampled.file;
+
+import javazoom.spi.mpeg.sampled.file.tag.MP3Tag;
+import javazoom.spi.mpeg.sampled.file.tag.TagParseEvent;
+import javazoom.spi.mpeg.sampled.file.tag.TagParseListener;
+
+/**
+ * This class (singleton) allow to be notified on shoutcast meta data
+ * while playing the stream (such as song title).
+ */
+public class IcyListener implements TagParseListener
+{
+	private static IcyListener instance = null;
+	private MP3Tag lastTag = null;
+	private String streamTitle = null;
+	private String streamUrl = null;
+	
+		
+	private IcyListener()
+	{
+		super();
+	}
+
+	public static synchronized IcyListener getInstance()
+	{
+		if (instance == null)
+		{
+			instance = new IcyListener();
+		}
+		return instance;		
+	}
+	
+	/* (non-Javadoc)
+	 * @see javazoom.spi.mpeg.sampled.file.tag.TagParseListener#tagParsed(javazoom.spi.mpeg.sampled.file.tag.TagParseEvent)
+	 */
+	public void tagParsed(TagParseEvent tpe)
+	{		
+		lastTag = tpe.getTag();
+		String name = lastTag.getName();
+		if ((name != null) && (name.equalsIgnoreCase("streamtitle")))
+		{
+			streamTitle = (String) lastTag.getValue();
+		}
+		else if ((name != null) && (name.equalsIgnoreCase("streamurl")))
+		{
+			streamUrl = (String) lastTag.getValue();
+		}	
+	}
+
+	/**
+	 * @return
+	 */
+	public MP3Tag getLastTag()
+	{
+		return lastTag;
+	}
+
+	/**
+	 * @param tag
+	 */
+	public void setLastTag(MP3Tag tag)
+	{
+		lastTag = tag;
+	}
+
+	/**
+	 * @return
+	 */
+	public String getStreamTitle()
+	{
+		return streamTitle;
+	}
+
+	/**
+	 * @return
+	 */
+	public String getStreamUrl()
+	{
+		return streamUrl;
+	}
+
+	/**
+	 * @param string
+	 */
+	public void setStreamTitle(String string)
+	{
+		streamTitle = string;
+	}
+
+	/**
+	 * @param string
+	 */
+	public void setStreamUrl(String string)
+	{
+		streamUrl = string;
+	}
+	
+	/**
+	 * Reset all properties.
+	 */
+	public void reset()
+	{
+		lastTag = null;
+		streamTitle = null;
+		streamUrl = null;		
+	}
+
+}

+ 106 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/MpegAudioFileFormat.java

@@ -0,0 +1,106 @@
+/*
+ * MpegAudioFileFormat.
+ *
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+package javazoom.spi.mpeg.sampled.file;
+
+import java.util.Map;
+
+import javax.sound.sampled.AudioFormat;
+
+import org.tritonus.share.sampled.file.TAudioFileFormat;
+
+/**
+ * @author JavaZOOM
+ */
+public class MpegAudioFileFormat extends TAudioFileFormat
+{
+	/**
+	 * Contructor.
+	 * @param type
+	 * @param audioFormat
+	 * @param nLengthInFrames
+	 * @param nLengthInBytes
+	 */
+	public MpegAudioFileFormat(Type type, AudioFormat audioFormat, int nLengthInFrames, int nLengthInBytes, Map properties)
+	{
+		super(type, audioFormat, nLengthInFrames, nLengthInBytes, properties);
+	}
+
+	/**
+	 * MP3 audio file format parameters.
+	 * Some parameters might be unavailable. So availability test is required before reading any parameter.
+	 *
+	 * <br>AudioFileFormat parameters.
+	 * <ul>
+	 * <li><b>duration</b> [Long], duration in microseconds.
+	 * <li><b>title</b> [String], Title of the stream.
+	 * <li><b>author</b> [String], Name of the artist of the stream.
+	 * <li><b>album</b> [String], Name of the album of the stream.
+	 * <li><b>date</b> [String], The date (year) of the recording or release of the stream.
+	 * <li><b>copyright</b> [String], Copyright message of the stream.
+	 * <li><b>comment</b> [String], Comment of the stream.
+	 * </ul>
+	 * <br>MP3 parameters.
+	 * <ul>
+	 * <li><b>mp3.version.mpeg</b> [String], mpeg version : 1,2 or 2.5
+	 * <li><b>mp3.version.layer</b> [String], layer version 1, 2 or 3
+	 * <li><b>mp3.version.encoding</b> [String], mpeg encoding : MPEG1, MPEG2-LSF, MPEG2.5-LSF
+	 * <li><b>mp3.channels</b> [Integer], number of channels 1 : mono, 2 : stereo.
+	 * <li><b>mp3.frequency.hz</b> [Integer], sampling rate in hz.
+	 * <li><b>mp3.bitrate.nominal.bps</b> [Integer], nominal bitrate in bps.
+	 * <li><b>mp3.length.bytes</b> [Integer], length in bytes.
+	 * <li><b>mp3.length.frames</b> [Integer], length in frames.
+	 * <li><b>mp3.framesize.bytes</b> [Integer], framesize of the first frame. framesize is not constant for VBR streams.
+	 * <li><b>mp3.framerate.fps</b> [Float], framerate in frames per seconds.
+	 * <li><b>mp3.header.pos</b> [Integer], position of first audio header (or ID3v2 size).
+	 * <li><b>mp3.vbr</b> [Boolean], vbr flag.
+	 * <li><b>mp3.vbr.scale</b> [Integer], vbr scale.
+	 * <li><b>mp3.crc</b> [Boolean], crc flag.
+	 * <li><b>mp3.original</b> [Boolean], original flag.
+	 * <li><b>mp3.copyright</b> [Boolean], copyright flag.
+	 * <li><b>mp3.padding</b> [Boolean], padding flag.
+	 * <li><b>mp3.mode</b> [Integer], mode 0:STEREO 1:JOINT_STEREO 2:DUAL_CHANNEL 3:SINGLE_CHANNEL
+	 * <li><b>mp3.id3tag.genre</b> [String], ID3 tag (v1 or v2) genre.
+	 * <li><b>mp3.id3tag.track</b> [String], ID3 tag (v1 or v2) track info.
+	 * <li><b>mp3.id3tag.encoded</b> [String], ID3 tag v2 encoded by info.
+	 * <li><b>mp3.id3tag.composer</b> [String], ID3 tag v2 composer info.
+	 * <li><b>mp3.id3tag.grouping</b> [String], ID3 tag v2 grouping info.
+	 * <li><b>mp3.id3tag.disc</b> [String], ID3 tag v2 track info.
+     * <li><b>mp3.id3tag.publisher</b> [String], ID3 tag v2 publisher info.
+     * <li><b>mp3.id3tag.orchestra</b> [String], ID3 tag v2 orchestra info.
+     * <li><b>mp3.id3tag.length</b> [String], ID3 tag v2 file length in seconds.
+	 * <li><b>mp3.id3tag.v2</b> [InputStream], ID3v2 frames.
+	 * <li><b>mp3.id3tag.v2.version</b> [String], ID3v2 major version (2=v2.2.0, 3=v2.3.0, 4=v2.4.0).
+	 * <li><b>mp3.shoutcast.metadata.key</b> [String], Shoutcast meta key with matching value.
+	 * <br>For instance :
+	 * <br>mp3.shoutcast.metadata.icy-irc=#shoutcast
+	 * <br>mp3.shoutcast.metadata.icy-metaint=8192
+	 * <br>mp3.shoutcast.metadata.icy-genre=Trance Techno Dance
+	 * <br>mp3.shoutcast.metadata.icy-url=http://www.di.fm
+	 * <br>and so on ...
+	 * </ul>
+	 */
+	public Map properties()
+	{
+		return super.properties();
+	}
+}

+ 830 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/MpegAudioFileReader.java

@@ -0,0 +1,830 @@
+/*
+ * MpegAudioFileReader.
+ *
+ * 10/10/05 : size computation bug fixed in parseID3v2Frames.
+ *            RIFF/MP3 header support added.
+ *            FLAC and MAC headers throw UnsupportedAudioFileException now.
+ *            "mp3.id3tag.publisher" (TPUB/TPB) added.
+ *            "mp3.id3tag.orchestra" (TPE2/TP2) added.
+ *            "mp3.id3tag.length" (TLEN/TLE) added.
+ *
+ * 08/15/05 : parseID3v2Frames improved.
+ *
+ * 12/31/04 : mp3spi.weak system property added to skip controls.
+ *
+ * 11/29/04 : ID3v2.2, v2.3 & v2.4 support improved.
+ *            "mp3.id3tag.composer" (TCOM/TCM) added
+ *            "mp3.id3tag.grouping" (TIT1/TT1) added
+ *            "mp3.id3tag.disc" (TPA/TPOS) added
+ *            "mp3.id3tag.encoded" (TEN/TENC) added
+ *            "mp3.id3tag.v2.version" added
+ *
+ * 11/28/04 : String encoding bug fix in chopSubstring method.
+ *
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+package javazoom.spi.mpeg.sampled.file;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.AccessControlException;
+import java.util.HashMap;
+import javax.sound.sampled.AudioFileFormat;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import javazoom.jl.decoder.Bitstream;
+import javazoom.jl.decoder.Header;
+import javazoom.spi.mpeg.sampled.file.tag.IcyInputStream;
+import javazoom.spi.mpeg.sampled.file.tag.MP3Tag;
+import org.tritonus.share.TDebug;
+import org.tritonus.share.sampled.file.TAudioFileReader;
+
+/**
+ * This class implements AudioFileReader for MP3 SPI.
+ */
+public class MpegAudioFileReader extends TAudioFileReader
+{
+    public static final String VERSION = "MP3SPI 1.9.5";
+    private final int SYNC = 0xFFE00000;
+    private String weak = null;
+    private final AudioFormat.Encoding[][] sm_aEncodings = {
+            { MpegEncoding.MPEG2L1, MpegEncoding.MPEG2L2, MpegEncoding.MPEG2L3 },
+            { MpegEncoding.MPEG1L1, MpegEncoding.MPEG1L2, MpegEncoding.MPEG1L3 },
+            { MpegEncoding.MPEG2DOT5L1, MpegEncoding.MPEG2DOT5L2, MpegEncoding.MPEG2DOT5L3 }, };
+    public static int INITAL_READ_LENGTH = 128000*32;
+    private static int MARK_LIMIT = INITAL_READ_LENGTH + 1;
+    static {
+    	String s = System.getProperty("marklimit");
+    	if (s != null)
+    	{
+    		try 
+    		{
+    			INITAL_READ_LENGTH = Integer.parseInt(s);
+    			MARK_LIMIT = INITAL_READ_LENGTH + 1;
+			} 
+    		catch (NumberFormatException e) 
+    		{
+				e.printStackTrace();
+			}
+    	}
+    }
+
+    private static final String[] id3v1genres = {
+          "Blues"
+          , "Classic Rock"
+          , "Country"
+          , "Dance"
+          , "Disco"
+          , "Funk"
+          , "Grunge"
+          , "Hip-Hop"
+          , "Jazz"
+          , "Metal"
+          , "New Age"
+          , "Oldies"
+          , "Other"
+          , "Pop"
+          , "R&B"
+          , "Rap"
+          , "Reggae"
+          , "Rock"
+          , "Techno"
+          , "Industrial"
+          , "Alternative"
+          , "Ska"
+          , "Death Metal"
+          , "Pranks"
+          , "Soundtrack"
+          , "Euro-Techno"
+          , "Ambient"
+          , "Trip-Hop"
+          , "Vocal"
+          , "Jazz+Funk"
+          , "Fusion"
+          , "Trance"
+          , "Classical"
+          , "Instrumental"
+          , "Acid"
+          , "House"
+          , "Game"
+          , "Sound Clip"
+          , "Gospel"
+          , "Noise"
+          , "AlternRock"
+          , "Bass"
+          , "Soul"
+          , "Punk"
+          , "Space"
+          , "Meditative"
+          , "Instrumental Pop"
+          , "Instrumental Rock"
+          , "Ethnic"
+          , "Gothic"
+          , "Darkwave"
+          , "Techno-Industrial"
+          , "Electronic"
+          , "Pop-Folk"
+          , "Eurodance"
+          , "Dream"
+          , "Southern Rock"
+          , "Comedy"
+          , "Cult"
+          , "Gangsta"
+          , "Top 40"
+          , "Christian Rap"
+          , "Pop/Funk"
+          , "Jungle"
+          , "Native American"
+          , "Cabaret"
+          , "New Wave"
+          , "Psychadelic"
+          , "Rave"
+          , "Showtunes"
+          , "Trailer"
+          , "Lo-Fi"
+          , "Tribal"
+          , "Acid Punk"
+          , "Acid Jazz"
+          , "Polka"
+          , "Retro"
+          , "Musical"
+          , "Rock & Roll"
+          , "Hard Rock"
+          , "Folk"
+          , "Folk-Rock"
+          , "National Folk"
+          , "Swing"
+          , "Fast Fusion"
+          , "Bebob"
+          , "Latin"
+          , "Revival"
+          , "Celtic"
+          , "Bluegrass"
+          , "Avantgarde"
+          , "Gothic Rock"
+          , "Progressive Rock"
+          , "Psychedelic Rock"
+          , "Symphonic Rock"
+          , "Slow Rock"
+          , "Big Band"
+          , "Chorus"
+          , "Easy Listening"
+          , "Acoustic"
+          , "Humour"
+          , "Speech"
+          , "Chanson"
+          , "Opera"
+          , "Chamber Music"
+          , "Sonata"
+          , "Symphony"
+          , "Booty Brass"
+          , "Primus"
+          , "Porn Groove"
+          , "Satire"
+          , "Slow Jam"
+          , "Club"
+          , "Tango"
+          , "Samba"
+          , "Folklore"
+          , "Ballad"
+          , "Power Ballad"
+          , "Rhythmic Soul"
+          , "Freestyle"
+          , "Duet"
+          , "Punk Rock"
+          , "Drum Solo"
+          , "A Capela"
+          , "Euro-House"
+          , "Dance Hall"
+          , "Goa"
+          , "Drum & Bass"
+          , "Club-House"
+          , "Hardcore"
+          , "Terror"
+          , "Indie"
+          , "BritPop"
+          , "Negerpunk"
+          , "Polsk Punk"
+          , "Beat"
+          , "Christian Gangsta Rap"
+          , "Heavy Metal"
+          , "Black Metal"
+          , "Crossover"
+          , "Contemporary Christian"
+          , "Christian Rock"
+          , "Merengue"
+          , "Salsa"
+          , "Thrash Metal"
+          , "Anime"
+          , "JPop"
+          , "SynthPop"
+          };
+
+    public MpegAudioFileReader()
+    {
+        super(MARK_LIMIT, true);
+        if (TDebug.TraceAudioFileReader) TDebug.out(VERSION);
+        try
+        {
+            weak = System.getProperty("mp3spi.weak");
+        }
+        catch (AccessControlException e)
+        {
+        }
+    }
+
+    /**
+     * Returns AudioFileFormat from File.
+     */
+    public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException
+    {
+        return super.getAudioFileFormat(file);
+    }
+
+    /**
+     * Returns AudioFileFormat from URL.
+     */
+    public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException
+    {
+        if (TDebug.TraceAudioFileReader)
+        {
+            TDebug.out("MpegAudioFileReader.getAudioFileFormat(URL): begin");
+        }
+        long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
+        URLConnection conn = url.openConnection();
+        // Tell shoucast server (if any) that SPI support shoutcast stream.
+        conn.setRequestProperty("Icy-Metadata", "1");
+        InputStream inputStream = conn.getInputStream();
+        AudioFileFormat audioFileFormat = null;
+        try
+        {
+            audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
+        }
+        finally
+        {
+            inputStream.close();
+        }
+        if (TDebug.TraceAudioFileReader)
+        {
+            TDebug.out("MpegAudioFileReader.getAudioFileFormat(URL): end");
+        }
+        return audioFileFormat;
+    }
+
+    /**
+     * Returns AudioFileFormat from inputstream and medialength.
+     */
+    public AudioFileFormat getAudioFileFormat(InputStream inputStream, long mediaLength) throws UnsupportedAudioFileException, IOException
+    {
+        if (TDebug.TraceAudioFileReader) TDebug.out(">MpegAudioFileReader.getAudioFileFormat(InputStream inputStream, long mediaLength): begin");
+        HashMap aff_properties = new HashMap();
+        HashMap af_properties = new HashMap();
+        int mLength = (int) mediaLength;
+        int size = inputStream.available();
+        PushbackInputStream pis = new PushbackInputStream(inputStream, MARK_LIMIT);
+        byte head[] = new byte[22];
+        pis.read(head);
+        if (TDebug.TraceAudioFileReader)
+        {
+            TDebug.out("InputStream : " + inputStream + " =>" + new String(head));
+        }
+
+        // Check for WAV, AU, and AIFF, Ogg Vorbis, Flac, MAC file formats.
+        // Next check for Shoutcast (supported) and OGG (unsupported) streams.
+        if ((head[0] == 'R') && (head[1] == 'I') && (head[2] == 'F') && (head[3] == 'F') && (head[8] == 'W') && (head[9] == 'A') && (head[10] == 'V') && (head[11] == 'E'))
+        {
+            if (TDebug.TraceAudioFileReader) TDebug.out("RIFF/WAV stream found");
+            int isPCM = ((head[21]<<8)&0x0000FF00) | ((head[20])&0x00000FF);
+            if (weak == null)
+            {
+                if (isPCM == 1) throw new UnsupportedAudioFileException("WAV PCM stream found");
+            }
+
+        }
+        else if ((head[0] == '.') && (head[1] == 's') && (head[2] == 'n') && (head[3] == 'd'))
+        {
+            if (TDebug.TraceAudioFileReader) TDebug.out("AU stream found");
+            if (weak == null) throw new UnsupportedAudioFileException("AU stream found");
+        }
+        else if ((head[0] == 'F') && (head[1] == 'O') && (head[2] == 'R') && (head[3] == 'M') && (head[8] == 'A') && (head[9] == 'I') && (head[10] == 'F') && (head[11] == 'F'))
+        {
+            if (TDebug.TraceAudioFileReader) TDebug.out("AIFF stream found");
+            if (weak == null) throw new UnsupportedAudioFileException("AIFF stream found");
+        }
+        else if (((head[0] == 'M') | (head[0] == 'm')) && ((head[1] == 'A') | (head[1] == 'a')) && ((head[2] == 'C') | (head[2] == 'c')))
+        {
+            if (TDebug.TraceAudioFileReader) TDebug.out("APE stream found");
+            if (weak == null) throw new UnsupportedAudioFileException("APE stream found");
+        }
+        else if (((head[0] == 'F') | (head[0] == 'f')) && ((head[1] == 'L') | (head[1] == 'l')) && ((head[2] == 'A') | (head[2] == 'a')) && ((head[3] == 'C') | (head[3] == 'c')))
+        {
+            if (TDebug.TraceAudioFileReader) TDebug.out("FLAC stream found");
+            if (weak == null) throw new UnsupportedAudioFileException("FLAC stream found");
+        }
+        // Shoutcast stream ?
+        else if (((head[0] == 'I') | (head[0] == 'i')) && ((head[1] == 'C') | (head[1] == 'c')) && ((head[2] == 'Y') | (head[2] == 'y')))
+        {
+            pis.unread(head);
+            // Load shoutcast meta data.
+            loadShoutcastInfo(pis, aff_properties);
+        }
+        // Ogg stream ?
+        else if (((head[0] == 'O') | (head[0] == 'o')) && ((head[1] == 'G') | (head[1] == 'g')) && ((head[2] == 'G') | (head[2] == 'g')))
+        {
+            if (TDebug.TraceAudioFileReader) TDebug.out("Ogg stream found");
+            if (weak == null) throw new UnsupportedAudioFileException("Ogg stream found");
+        }
+        // No, so pushback.
+        else
+        {
+            pis.unread(head);
+        }
+        // MPEG header info.
+        int nVersion = AudioSystem.NOT_SPECIFIED;
+        int nLayer = AudioSystem.NOT_SPECIFIED;
+        int nSFIndex = AudioSystem.NOT_SPECIFIED;
+        int nMode = AudioSystem.NOT_SPECIFIED;
+        int FrameSize = AudioSystem.NOT_SPECIFIED;
+        int nFrameSize = AudioSystem.NOT_SPECIFIED;
+        int nFrequency = AudioSystem.NOT_SPECIFIED;
+        int nTotalFrames = AudioSystem.NOT_SPECIFIED;
+        float FrameRate = AudioSystem.NOT_SPECIFIED;
+        int BitRate = AudioSystem.NOT_SPECIFIED;
+        int nChannels = AudioSystem.NOT_SPECIFIED;
+        int nHeader = AudioSystem.NOT_SPECIFIED;
+        int nTotalMS = AudioSystem.NOT_SPECIFIED;
+        boolean nVBR = false;
+        AudioFormat.Encoding encoding = null;
+        try
+        {
+            Bitstream m_bitstream = new Bitstream(pis);
+            int streamPos = m_bitstream.header_pos();
+            aff_properties.put("mp3.header.pos", new Integer(streamPos));
+            Header m_header = m_bitstream.readFrame();
+            // nVersion = 0 => MPEG2-LSF (Including MPEG2.5), nVersion = 1 => MPEG1
+            nVersion = m_header.version();
+            if (nVersion == 2) aff_properties.put("mp3.version.mpeg", Float.toString(2.5f));
+            else aff_properties.put("mp3.version.mpeg", Integer.toString(2 - nVersion));
+            // nLayer = 1,2,3
+            nLayer = m_header.layer();
+            aff_properties.put("mp3.version.layer", Integer.toString(nLayer));
+            nSFIndex = m_header.sample_frequency();
+            nMode = m_header.mode();
+            aff_properties.put("mp3.mode", new Integer(nMode));
+            nChannels = nMode == 3 ? 1 : 2;
+            aff_properties.put("mp3.channels", new Integer(nChannels));
+            nVBR = m_header.vbr();
+            af_properties.put("vbr", new Boolean(nVBR));
+            aff_properties.put("mp3.vbr", new Boolean(nVBR));
+            aff_properties.put("mp3.vbr.scale", new Integer(m_header.vbr_scale()));
+            FrameSize = m_header.calculate_framesize();
+            aff_properties.put("mp3.framesize.bytes", new Integer(FrameSize));
+            if (FrameSize < 0) throw new UnsupportedAudioFileException("Invalid FrameSize : " + FrameSize);
+            nFrequency = m_header.frequency();
+            aff_properties.put("mp3.frequency.hz", new Integer(nFrequency));
+            FrameRate = (float) ((1.0 / (m_header.ms_per_frame())) * 1000.0);
+            aff_properties.put("mp3.framerate.fps", new Float(FrameRate));
+            if (FrameRate < 0) throw new UnsupportedAudioFileException("Invalid FrameRate : " + FrameRate);
+            // Remove heading tag length from real stream length.
+            int tmpLength = mLength;
+            if ((streamPos > 0) && (mLength != AudioSystem.NOT_SPECIFIED) && (streamPos < mLength)) tmpLength = tmpLength - streamPos;
+            if (mLength != AudioSystem.NOT_SPECIFIED)
+            {
+                aff_properties.put("mp3.length.bytes", new Integer(mLength));
+                nTotalFrames = m_header.max_number_of_frames(tmpLength);
+                aff_properties.put("mp3.length.frames", new Integer(nTotalFrames));
+            }
+            BitRate = m_header.bitrate();
+            af_properties.put("bitrate", new Integer(BitRate));
+            aff_properties.put("mp3.bitrate.nominal.bps", new Integer(BitRate));
+            nHeader = m_header.getSyncHeader();
+            encoding = sm_aEncodings[nVersion][nLayer - 1];
+            aff_properties.put("mp3.version.encoding", encoding.toString());
+            if (mLength != AudioSystem.NOT_SPECIFIED)
+            {
+                nTotalMS = Math.round(m_header.total_ms(tmpLength));
+                aff_properties.put("duration", new Long((long) nTotalMS * 1000L));
+            }
+            aff_properties.put("mp3.copyright", new Boolean(m_header.copyright()));
+            aff_properties.put("mp3.original", new Boolean(m_header.original()));
+            aff_properties.put("mp3.crc", new Boolean(m_header.checksums()));
+            aff_properties.put("mp3.padding", new Boolean(m_header.padding()));
+            InputStream id3v2 = m_bitstream.getRawID3v2();
+            if (id3v2 != null)
+            {
+                aff_properties.put("mp3.id3tag.v2", id3v2);
+                parseID3v2Frames(id3v2, aff_properties);
+            }
+            if (TDebug.TraceAudioFileReader) TDebug.out(m_header.toString());
+        }
+        catch (Exception e)
+        {
+            if (TDebug.TraceAudioFileReader) TDebug.out("not a MPEG stream:" + e.getMessage());
+            throw new UnsupportedAudioFileException("not a MPEG stream:" + e.getMessage());
+        }
+        // Deeper checks ?
+        int cVersion = (nHeader >> 19) & 0x3;
+        if (cVersion == 1)
+        {
+            if (TDebug.TraceAudioFileReader) TDebug.out("not a MPEG stream: wrong version");
+            throw new UnsupportedAudioFileException("not a MPEG stream: wrong version");
+        }
+        int cSFIndex = (nHeader >> 10) & 0x3;
+        if (cSFIndex == 3)
+        {
+            if (TDebug.TraceAudioFileReader) TDebug.out("not a MPEG stream: wrong sampling rate");
+            throw new UnsupportedAudioFileException("not a MPEG stream: wrong sampling rate");
+        }
+        // Look up for ID3v1 tag
+        if ((size == mediaLength) && (mediaLength != AudioSystem.NOT_SPECIFIED))
+        {
+            FileInputStream fis = (FileInputStream) inputStream;
+            byte[] id3v1 = new byte[128];
+            long bytesSkipped = fis.skip(inputStream.available() - id3v1.length);
+            int read = fis.read(id3v1, 0, id3v1.length);
+            if ((id3v1[0] == 'T') && (id3v1[1] == 'A') && (id3v1[2] == 'G'))
+            {
+                parseID3v1Frames(id3v1, aff_properties);
+            }
+        }
+        AudioFormat format = new MpegAudioFormat(encoding, (float) nFrequency, AudioSystem.NOT_SPECIFIED // SampleSizeInBits - The size of a sample
+                , nChannels // Channels - The number of channels
+                , -1 // The number of bytes in each frame
+                , FrameRate // FrameRate - The number of frames played or recorded per second
+                , true, af_properties);
+        return new MpegAudioFileFormat(MpegFileFormatType.MP3, format, nTotalFrames, mLength, aff_properties);
+    }
+
+    /**
+     * Returns AudioInputStream from file.
+     */
+    public AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException
+    {
+        if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(File file)");
+        InputStream inputStream = new FileInputStream(file);
+        try
+        {
+            return getAudioInputStream(inputStream);
+        }
+        catch (UnsupportedAudioFileException e)
+        {
+            if (inputStream != null) inputStream.close();
+            throw e;
+        }
+        catch (IOException e)
+        {
+            if (inputStream != null) inputStream.close();
+            throw e;
+        }
+    }
+
+    /**
+     * Returns AudioInputStream from url.
+     */
+    public AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException
+    {
+        if (TDebug.TraceAudioFileReader)
+        {
+            TDebug.out("MpegAudioFileReader.getAudioInputStream(URL): begin");
+        }
+        long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
+        URLConnection conn = url.openConnection();
+        // Tell shoucast server (if any) that SPI support shoutcast stream.
+        boolean isShout = false;
+        int toRead = 4;
+        byte[] head = new byte[toRead];
+        conn.setRequestProperty("Icy-Metadata", "1");
+        BufferedInputStream bInputStream = new BufferedInputStream(conn.getInputStream());
+        bInputStream.mark(toRead);
+        int read = bInputStream.read(head, 0, toRead);
+        if ((read > 2) && (((head[0] == 'I') | (head[0] == 'i')) && ((head[1] == 'C') | (head[1] == 'c')) && ((head[2] == 'Y') | (head[2] == 'y')))) isShout = true;
+        bInputStream.reset();
+        InputStream inputStream = null;
+        // Is is a shoutcast server ?
+        if (isShout == true)
+        {
+            // Yes
+            IcyInputStream icyStream = new IcyInputStream(bInputStream);
+            icyStream.addTagParseListener(IcyListener.getInstance());
+            inputStream = icyStream;
+        }
+        else
+        {
+            // No, is Icecast 2 ?
+            String metaint = conn.getHeaderField("icy-metaint");
+            if (metaint != null)
+            {
+                // Yes, it might be icecast 2 mp3 stream.
+                IcyInputStream icyStream = new IcyInputStream(bInputStream, metaint);
+                icyStream.addTagParseListener(IcyListener.getInstance());
+                inputStream = icyStream;
+            }
+            else
+            {
+                // No
+                inputStream = bInputStream;
+            }
+        }
+        AudioInputStream audioInputStream = null;
+        try
+        {
+            audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
+        }
+        catch (UnsupportedAudioFileException e)
+        {
+            inputStream.close();
+            throw e;
+        }
+        catch (IOException e)
+        {
+            inputStream.close();
+            throw e;
+        }
+        if (TDebug.TraceAudioFileReader)
+        {
+            TDebug.out("MpegAudioFileReader.getAudioInputStream(URL): end");
+        }
+        return audioInputStream;
+    }
+
+    /**
+     * Return the AudioInputStream from the given InputStream.
+     */
+    public AudioInputStream getAudioInputStream(InputStream inputStream) throws UnsupportedAudioFileException, IOException
+    {
+        if (TDebug.TraceAudioFileReader) TDebug.out("MpegAudioFileReader.getAudioInputStream(InputStream inputStream)");
+        if (!inputStream.markSupported()) inputStream = new BufferedInputStream(inputStream);
+        return super.getAudioInputStream(inputStream);
+    }
+
+    /**
+     * Parser ID3v1 frames
+     * @param frames
+     * @param props
+     */
+    protected void parseID3v1Frames(byte[] frames, HashMap props)
+    {
+        if (TDebug.TraceAudioFileReader) TDebug.out("Parsing ID3v1");
+        String tag = null;
+        try
+        {
+            tag = new String(frames, 0, frames.length, "ISO-8859-1");
+        }
+        catch (UnsupportedEncodingException e)
+        {
+            tag = new String(frames, 0, frames.length);
+            if (TDebug.TraceAudioFileReader) TDebug.out("Cannot use ISO-8859-1");
+        }
+        if (TDebug.TraceAudioFileReader) TDebug.out("ID3v1 frame dump='" + tag + "'");
+        int start = 3;
+        String titlev1 = chopSubstring(tag, start, start += 30);
+        String titlev2 = (String) props.get("title");
+        if (((titlev2 == null) || (titlev2.length() == 0)) && (titlev1 != null)) props.put("title", titlev1);
+        String artistv1 = chopSubstring(tag, start, start += 30);
+        String artistv2 = (String) props.get("author");
+        if (((artistv2 == null) || (artistv2.length() == 0)) && (artistv1 != null)) props.put("author", artistv1);
+        String albumv1 = chopSubstring(tag, start, start += 30);
+        String albumv2 = (String) props.get("album");
+        if (((albumv2 == null) || (albumv2.length() == 0)) && (albumv1 != null)) props.put("album", albumv1);
+        String yearv1 = chopSubstring(tag, start, start += 4);
+        String yearv2 = (String) props.get("year");
+        if (((yearv2 == null) || (yearv2.length() == 0)) && (yearv1 != null)) props.put("date", yearv1);
+        String commentv1 = chopSubstring(tag, start, start += 28);
+        String commentv2 = (String) props.get("comment");
+        if (((commentv2 == null) || (commentv2.length() == 0)) && (commentv1 != null)) props.put("comment", commentv1);
+        String trackv1 = "" + ((int) (frames[126] & 0xff));
+        String trackv2 = (String) props.get("mp3.id3tag.track");
+        if (((trackv2 == null) || (trackv2.length() == 0)) && (trackv1 != null)) props.put("mp3.id3tag.track", trackv1);
+        int genrev1 = (int) (frames[127] & 0xff);
+        if ((genrev1 >= 0) && (genrev1 < id3v1genres.length))
+        {
+            String genrev2 = (String) props.get("mp3.id3tag.genre");
+            if (((genrev2 == null) || (genrev2.length() == 0))) props.put("mp3.id3tag.genre", id3v1genres[genrev1]);
+        }
+        if (TDebug.TraceAudioFileReader) TDebug.out("ID3v1 parsed");
+    }
+
+    /**
+     * Extract
+     * @param s
+     * @param start
+     * @param end
+     * @return
+     */
+    private String chopSubstring(String s, int start, int end)
+    {
+        String str = null;
+        // 11/28/04 - String encoding bug fix.
+        try
+        {
+            str = s.substring(start, end);
+            int loc = str.indexOf('\0');
+            if (loc != -1) str = str.substring(0, loc);
+        }
+        catch (StringIndexOutOfBoundsException e)
+        {
+            // Skip encoding issues.
+            if (TDebug.TraceAudioFileReader) TDebug.out("Cannot chopSubString " + e.getMessage());
+        }
+        return str;
+    }
+
+    /**
+     * Parse ID3v2 frames to add album (TALB), title (TIT2), date (TYER), author (TPE1), copyright (TCOP), comment (COMM) ...
+     * @param frames
+     * @param props
+     */
+    protected void parseID3v2Frames(InputStream frames, HashMap props)
+    {
+        if (TDebug.TraceAudioFileReader) TDebug.out("Parsing ID3v2");
+        byte[] bframes = null;
+        int size = -1;
+        try
+        {
+            size = frames.available();
+            bframes = new byte[size];
+            frames.mark(size);
+            frames.read(bframes);
+            frames.reset();
+        }
+        catch (IOException e)
+        {
+            if (TDebug.TraceAudioFileReader) TDebug.out("Cannot parse ID3v2 :" + e.getMessage());
+        }
+        if (!"ID3".equals(new String(bframes, 0, 3)))
+        {
+            TDebug.out("No ID3v2 header found!");
+            return;
+        }
+        int v2version = (int) (bframes[3] & 0xFF);
+        props.put("mp3.id3tag.v2.version", String.valueOf(v2version));
+        if (v2version < 2 || v2version > 4)
+        {
+            TDebug.out("Unsupported ID3v2 version " + v2version + "!");
+            return;
+        }
+        try
+        {
+            if (TDebug.TraceAudioFileReader) TDebug.out("ID3v2 frame dump='" + new String(bframes, 0, bframes.length) + "'");
+            /* ID3 tags : http://www.unixgods.org/~tilo/ID3/docs/ID3_comparison.html */
+            String value = null;
+            for (int i = 10; i < bframes.length && bframes[i] > 0; i += size)
+            {
+                if (v2version == 3 || v2version == 4)
+                {
+                    // ID3v2.3 & ID3v2.4
+                    String code = new String(bframes, i, 4);
+                    size = (int) ((bframes[i + 4] << 24) & 0xFF000000 | (bframes[i + 5] << 16) & 0x00FF0000 | (bframes[i + 6] << 8) & 0x0000FF00 | (bframes[i + 7]) & 0x000000FF);
+                    i += 10;
+                    if ((code.equals("TALB")) || (code.equals("TIT2")) || (code.equals("TYER")) ||
+                        (code.equals("TPE1")) || (code.equals("TCOP")) || (code.equals("COMM")) ||
+                        (code.equals("TCON")) || (code.equals("TRCK")) || (code.equals("TPOS")) ||
+                        (code.equals("TDRC")) || (code.equals("TCOM")) || (code.equals("TIT1")) ||
+                        (code.equals("TENC")) || (code.equals("TPUB")) || (code.equals("TPE2")) ||
+                        (code.equals("TLEN")) )
+                    {
+                        if (code.equals("COMM")) value = parseText(bframes, i, size, 5);
+                        else value = parseText(bframes, i, size, 1);
+                        if ((value != null) && (value.length() > 0))
+                        {
+                            if (code.equals("TALB")) props.put("album", value);
+                            else if (code.equals("TIT2")) props.put("title", value);
+                            else if (code.equals("TYER")) props.put("date", value);
+                            // ID3v2.4 date fix.
+                            else if (code.equals("TDRC")) props.put("date", value);
+                            else if (code.equals("TPE1")) props.put("author", value);
+                            else if (code.equals("TCOP")) props.put("copyright", value);
+                            else if (code.equals("COMM")) props.put("comment", value);
+                            else if (code.equals("TCON")) props.put("mp3.id3tag.genre", value);
+                            else if (code.equals("TRCK")) props.put("mp3.id3tag.track", value);
+                            else if (code.equals("TPOS")) props.put("mp3.id3tag.disc", value);
+                            else if (code.equals("TCOM")) props.put("mp3.id3tag.composer", value);
+                            else if (code.equals("TIT1")) props.put("mp3.id3tag.grouping", value);
+                            else if (code.equals("TENC")) props.put("mp3.id3tag.encoded", value);
+                            else if (code.equals("TPUB")) props.put("mp3.id3tag.publisher", value);
+                            else if (code.equals("TPE2")) props.put("mp3.id3tag.orchestra", value);
+                            else if (code.equals("TLEN")) props.put("mp3.id3tag.length", value);
+                        }
+                    }
+                }
+                else
+                {
+                    // ID3v2.2
+                    String scode = new String(bframes, i, 3);
+                    size = (int) (0x00000000) + (bframes[i + 3] << 16) + (bframes[i + 4] << 8) + (bframes[i + 5]);
+                    i += 6;
+                    if ((scode.equals("TAL")) || (scode.equals("TT2")) || (scode.equals("TP1")) ||
+                        (scode.equals("TYE")) || (scode.equals("TRK")) || (scode.equals("TPA")) ||
+                        (scode.equals("TCR")) || (scode.equals("TCO")) || (scode.equals("TCM")) ||
+                        (scode.equals("COM")) || (scode.equals("TT1")) || (scode.equals("TEN")) ||
+                        (scode.equals("TPB")) || (scode.equals("TP2")) || (scode.equals("TLE")) )
+                    {
+                        if (scode.equals("COM")) value = parseText(bframes, i, size, 5);
+                        else value = parseText(bframes, i, size, 1);
+                        if ((value != null) && (value.length() > 0))
+                        {
+                            if (scode.equals("TAL")) props.put("album", value);
+                            else if (scode.equals("TT2")) props.put("title", value);
+                            else if (scode.equals("TYE")) props.put("date", value);
+                            else if (scode.equals("TP1")) props.put("author", value);
+                            else if (scode.equals("TCR")) props.put("copyright", value);
+                            else if (scode.equals("COM")) props.put("comment", value);
+                            else if (scode.equals("TCO")) props.put("mp3.id3tag.genre", value);
+                            else if (scode.equals("TRK")) props.put("mp3.id3tag.track", value);
+                            else if (scode.equals("TPA")) props.put("mp3.id3tag.disc", value);
+                            else if (scode.equals("TCM")) props.put("mp3.id3tag.composer", value);
+                            else if (scode.equals("TT1")) props.put("mp3.id3tag.grouping", value);
+                            else if (scode.equals("TEN")) props.put("mp3.id3tag.encoded", value);
+                            else if (scode.equals("TPB")) props.put("mp3.id3tag.publisher", value);
+                            else if (scode.equals("TP2")) props.put("mp3.id3tag.orchestra", value);
+                            else if (scode.equals("TLE")) props.put("mp3.id3tag.length", value);
+                        }
+                    }
+                }
+            }
+        }
+        catch (RuntimeException e)
+        {
+            // Ignore all parsing errors.
+            if (TDebug.TraceAudioFileReader) TDebug.out("Cannot parse ID3v2 :" + e.getMessage());
+        }
+        if (TDebug.TraceAudioFileReader) TDebug.out("ID3v2 parsed");
+    }
+
+    /**
+     * Parse Text Frames.
+     *
+     * @param bframes
+     * @param offset
+     * @param size
+     * @param skip
+     * @return
+     */
+    protected String parseText(byte[] bframes, int offset, int size, int skip)
+    {
+        String value = null;
+        try
+        {
+            String[] ENC_TYPES = { "ISO-8859-1", "UTF16", "UTF-16BE", "UTF-8" };
+            value = new String(bframes, offset + skip, size - skip, ENC_TYPES[bframes[offset]]);
+            value = chopSubstring(value, 0, value.length());
+        }
+        catch (UnsupportedEncodingException e)
+        {
+            if (TDebug.TraceAudioFileReader) TDebug.out("ID3v2 Encoding error :" + e.getMessage());
+        }
+        return value;
+    }
+
+    /**
+     * Load shoutcast (ICY) info.
+     *
+     * @param input
+     * @param props
+     * @throws IOException
+     */
+    protected void loadShoutcastInfo(InputStream input, HashMap props) throws IOException
+    {
+        IcyInputStream icy = new IcyInputStream(new BufferedInputStream(input));
+        HashMap metadata = icy.getTagHash();
+        MP3Tag titleMP3Tag = icy.getTag("icy-name");
+        if (titleMP3Tag != null) props.put("title", ((String) titleMP3Tag.getValue()).trim());
+        MP3Tag[] meta = icy.getTags();
+        if (meta != null)
+        {
+            StringBuffer metaStr = new StringBuffer();
+            for (int i = 0; i < meta.length; i++)
+            {
+                String key = meta[i].getName();
+                String value = ((String) icy.getTag(key).getValue()).trim();
+                props.put("mp3.shoutcast.metadata." + key, value);
+            }
+        }
+    }
+}

+ 67 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/MpegAudioFormat.java

@@ -0,0 +1,67 @@
+/*
+ * MpegAudioFormat.
+ * 
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ *  
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+
+package javazoom.spi.mpeg.sampled.file;
+
+import java.util.Map;
+
+import javax.sound.sampled.AudioFormat;
+
+import org.tritonus.share.sampled.TAudioFormat;
+
+/**
+ * @author JavaZOOM
+ */
+public class MpegAudioFormat extends TAudioFormat
+{	
+	/**
+	 * Constructor.
+	 * @param encoding
+	 * @param nFrequency
+	 * @param SampleSizeInBits
+	 * @param nChannels
+	 * @param FrameSize
+	 * @param FrameRate
+	 * @param isBigEndian
+	 * @param properties
+	 */
+	public MpegAudioFormat(AudioFormat.Encoding encoding, float nFrequency, int SampleSizeInBits, int nChannels, int FrameSize, float FrameRate, boolean isBigEndian, Map properties)
+	{
+		super(encoding, nFrequency, SampleSizeInBits, nChannels, FrameSize, FrameRate, isBigEndian, properties);
+	}
+
+	/**
+	 * MP3 audio format parameters. 
+	 * Some parameters might be unavailable. So availability test is required before reading any parameter.  
+	 *
+	 * <br>AudioFormat parameters.
+	 * <ul>
+	 * <li><b>bitrate</b> [Integer], bitrate in bits per seconds, average bitrate for VBR enabled stream.
+	 * <li><b>vbr</b> [Boolean], VBR flag.
+	 * </ul>
+	 */
+	public Map properties()
+	{
+		return super.properties();	
+	}	
+}

+ 47 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/MpegEncoding.java

@@ -0,0 +1,47 @@
+/*
+ * MpegEncoding.
+ * 
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ *  
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+
+package	javazoom.spi.mpeg.sampled.file;
+
+import javax.sound.sampled.AudioFormat;
+
+/**	
+ * Encodings used by the MPEG audio decoder.
+ */
+public class MpegEncoding extends AudioFormat.Encoding
+{
+	public static final AudioFormat.Encoding	MPEG1L1 = new MpegEncoding("MPEG1L1");
+	public static final AudioFormat.Encoding	MPEG1L2 = new MpegEncoding("MPEG1L2");
+	public static final AudioFormat.Encoding	MPEG1L3 = new MpegEncoding("MPEG1L3");
+	public static final AudioFormat.Encoding	MPEG2L1 = new MpegEncoding("MPEG2L1");
+	public static final AudioFormat.Encoding	MPEG2L2 = new MpegEncoding("MPEG2L2");
+	public static final AudioFormat.Encoding	MPEG2L3 = new MpegEncoding("MPEG2L3");
+	public static final AudioFormat.Encoding	MPEG2DOT5L1 = new MpegEncoding("MPEG2DOT5L1");
+	public static final AudioFormat.Encoding	MPEG2DOT5L2 = new MpegEncoding("MPEG2DOT5L2");
+	public static final AudioFormat.Encoding	MPEG2DOT5L3 = new MpegEncoding("MPEG2DOT5L3");
+
+	public MpegEncoding(String strName)
+	{
+		super(strName);
+	}
+}

+ 40 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/MpegFileFormatType.java

@@ -0,0 +1,40 @@
+/*
+ * MpegFileFormatType.
+ * 
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ *  
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+
+package	javazoom.spi.mpeg.sampled.file;
+
+import javax.sound.sampled.AudioFileFormat;
+
+/**	
+ *  FileFormatTypes used by the MPEG audio decoder.
+ */
+public class MpegFileFormatType extends	AudioFileFormat.Type
+{
+	public static final AudioFileFormat.Type	MPEG = new MpegFileFormatType("MPEG", "mpeg");
+	public static final AudioFileFormat.Type	MP3 = new MpegFileFormatType("MP3", "mp3");
+
+	public MpegFileFormatType(String strName, String strExtension)
+	{
+		super(strName, strExtension);
+	}
+}

+ 423 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/IcyInputStream.java

@@ -0,0 +1,423 @@
+/*
+ * IcyInputStream.
+ *
+ * jicyshout : http://sourceforge.net/projects/jicyshout/
+ *
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+
+package javazoom.spi.mpeg.sampled.file.tag;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+
+/** An BufferedInputStream that parses Shoutcast's "icy" metadata
+    from the stream.  Gets headers at the beginning and if the
+    "icy-metaint" tag is found, it parses and strips in-stream
+    metadata.
+    <p>
+    <b>The deal with metaint</b>: Icy streams don't try to put
+    tags between MP3 frames the way that ID3 does.  Instead, it
+    requires the client to strip metadata from the stream before
+    it hits the decoder.  You get an
+    <code>icy-metaint</code> name/val in the beginning of the
+    stream iff you sent "Icy-Metadata" with value "1" in the
+    request headers (SimpleMP3DataSource does this if the
+    "parseStreamMetadata" boolean is true).  If this is the case
+    then the value of icy-metaint is the amount of real data
+    between metadata blocks.  Each block begins with an int
+    indicating how much metadata there is -- the block is this
+    value times 16 (it can be, and often is, 0).
+    <p>
+    Originally thought that "icy" implied Icecast, but this is
+    completely wrong -- real Icecast servers, found through
+    www.icecast.net and typified by URLs with a trailing directory
+    (like CalArts School of Music - http://65.165.174.100:8000/som)
+    do not have the "ICY 200 OK" magic string or any of the
+    CRLF-separated headers.  Apparently, "icy" means "Shoutcast".
+    Yep, that's weird.
+    @author Chris Adamson, invalidname@mac.com
+ */
+public class IcyInputStream
+	extends BufferedInputStream
+	implements MP3MetadataParser {
+
+	public static boolean DEBUG = false;
+
+	MP3TagParseSupport tagParseSupport;
+	/** inline tags are delimited by ';', also filter out
+	    null bytes
+	 */
+	protected static final String INLINE_TAG_SEPARATORS = ";\u0000";
+	/* looks like icy streams start start with
+	   ICY 200 OK\r\n
+	   then the tags are like
+	   icy-notice1:<BR>This stream requires <a href="http://www.winamp.com/">Winamp</a><BR>\r\n
+	   icy-notice2:SHOUTcast Distributed Network Audio Server/win32 v1.8.2<BR>\r\n
+	   icy-name:Core-upt Radio\r\n
+	   icy-genre:Punk Ska Emo\r\n
+	   icy-url:http://www.core-uptrecords.com\r\n
+	   icy-pub:1\r\n
+	   icy-metaint:8192\r\n
+	   icy-br:56\r\n
+	   \r\n (signifies end of headers)
+	   we only get icy-metaint if the http request that created
+	   this stream sent the header "icy-metadata:1"
+	   //
+	   in in-line metadata, we read a byte that tells us how
+	   many 16-byte blocks there are (presumably, we still use
+	   \r\n for the separator... the block is padded out with
+	   0x00's that we can ignore)
+
+	   // when server is full/down/etc, we get the following for
+	   // one of the notice lines:
+	   icy-notice2:This server has reached its user limit<BR>
+	       or
+	   icy-notice2:The resource requested is currently unavailable<BR>
+	 */
+	/** Tags that have been discovered in the stream.
+	 */
+	HashMap tags;
+	/** Buffer for readCRLF line... note this limits lines to
+	    1024 chars (I've read that WinAmp barfs at 128, so
+	    this is generous)
+	 */
+	protected byte[] crlfBuffer = new byte[1024];
+	/** value of the "metaint" tag, which tells us how many bytes
+	    of real data are between the metadata tags.  if -1, this stream
+	    does not have metadata after the header.
+	 */
+	protected int metaint = -1;
+	/** how many bytes of real data remain before the next
+	    block of metadata.  Only meaningful if metaint != -1.
+	 */
+	protected int bytesUntilNextMetadata = -1;
+	// TODO: comment for constructor
+	/** Reads the initial headers of the stream and adds
+	    tags appropriatly.  Gets set up to find, read,
+	    and strip blocks of in-line metadata if the
+	    <code>icy-metaint</code> header is found.
+	 */
+	public IcyInputStream(InputStream in) throws IOException {
+		super(in);
+		tags = new HashMap();
+		tagParseSupport = new MP3TagParseSupport();
+		// read the initial tags here, including the metaint
+		// and set the counter for how far we read until
+		// the next metadata block (if any).
+		readInitialHeaders();
+		IcyTag metaIntTag = (IcyTag) getTag("icy-metaint");
+		if (DEBUG) System.out.println("METATAG:"+metaIntTag);
+		if (metaIntTag != null) {
+			String metaIntString = metaIntTag.getValueAsString();
+			try {
+				metaint = Integer.parseInt(metaIntString.trim());
+				if (DEBUG) System.out.println("METAINT:"+metaint);
+				bytesUntilNextMetadata = metaint;
+			}
+			catch (NumberFormatException nfe) {
+			}
+		}
+	}
+
+	/**
+	 * IcyInputStream constructor for know meta-interval (Icecast 2)
+	 * @param in
+	 * @param metaint
+	 * @throws IOException
+	 */
+	public IcyInputStream(InputStream in, String metaIntString) throws IOException {
+		super(in);
+		tags = new HashMap();
+		tagParseSupport = new MP3TagParseSupport();
+		try
+		{
+			metaint = Integer.parseInt(metaIntString.trim());
+			if (DEBUG) System.out.println("METAINT:"+metaint);
+			bytesUntilNextMetadata = metaint;
+		}
+		catch (NumberFormatException nfe) {
+		}
+	}
+
+	/** Assuming we're at the top of the stream, read lines one
+	    by one until we hit a completely blank \r\n.  Parse the
+	    data as IcyTags.
+	 */
+	protected void readInitialHeaders() throws IOException {
+		String line = null;
+		while (!((line = readCRLFLine()).equals(""))) {
+			int colonIndex = line.indexOf(':');
+			// does it have a ':' separator
+			if (colonIndex == -1)
+				continue;
+			IcyTag tag =
+				new IcyTag(
+					line.substring(0, colonIndex),
+					line.substring(colonIndex + 1));
+			//System.out.println(tag);
+			addTag(tag);
+		}
+	}
+	/** Read everything up to the next CRLF, return it as
+	    a String.
+	 */
+	protected String readCRLFLine() throws IOException {
+		int i = 0;
+		for (; i < crlfBuffer.length; i++) {
+			byte aByte = (byte) read();
+			if (aByte == '\r') {
+				// possible end of line
+				byte anotherByte = (byte) read();
+				i++; // since we read again
+				if (anotherByte == '\n') {
+					break; // break out of while
+				}
+				else {
+					// oops, not end of line - put these in array
+					crlfBuffer[i - 1] = aByte;
+					crlfBuffer[i] = anotherByte;
+				}
+			}
+			else {
+				// if not \r
+				crlfBuffer[i] = aByte;
+			}
+		} // for
+		// get the string from the byte[].  i is 1 too high because of
+		// read-ahead in crlf block
+		return new String(crlfBuffer, 0, i - 1);
+	}
+	/** Reads and returns a single byte.
+	    If the next byte is a metadata block, then that
+	    block is read, stripped, and parsed before reading
+	    and returning the first byte after the metadata block.
+	 */
+	public int read() throws IOException {
+		if (bytesUntilNextMetadata > 0) {
+			bytesUntilNextMetadata--;
+			return super.read();
+		}
+		else if (bytesUntilNextMetadata == 0) {
+			// we need to read next metadata block
+			readMetadata();
+			bytesUntilNextMetadata = metaint - 1;
+			// -1 because we read byte on next line
+			return super.read();
+		}
+		else {
+			// no metadata in this stream
+			return super.read();
+		}
+	}
+	/** Reads a block of bytes.  If the next byte is known
+	    to be a block of metadata, then that is read, parsed,
+	    and stripped, and then a block of bytes is read and
+	    returned.
+	    Otherwise, it may read up to but
+	    not into the next metadata block if
+	    <code>bytesUntilNextMetadata &lt; length</code>
+	 */
+	public int read(byte[] buf, int offset, int length) throws IOException {
+		// if not on metadata, do the usual read so long as we
+		// don't read past metadata
+		if (bytesUntilNextMetadata > 0) {
+			int adjLength = Math.min(length, bytesUntilNextMetadata);
+			int got = super.read(buf, offset, adjLength);
+			bytesUntilNextMetadata -= got;
+			return got;
+		}
+		else if (bytesUntilNextMetadata == 0) {
+			// read/parse the metadata
+			readMetadata();
+			// now as above, except that we reset
+			// bytesUntilNextMetadata differently
+
+			//int adjLength = Math.min(length, bytesUntilNextMetadata);
+			//int got = super.read(buf, offset, adjLength);
+			//bytesUntilNextMetadata = metaint - got;
+
+			// Chop Fix - JavaZOOM (3 lines above seem buggy)
+			bytesUntilNextMetadata = metaint;
+			int adjLength = Math.min(length, bytesUntilNextMetadata);
+			int got = super.read(buf, offset, adjLength);
+			bytesUntilNextMetadata -= got;
+			// End fix - JavaZOOM
+
+
+			return got;
+		}
+		else {
+			// not even reading metadata
+			return super.read(buf, offset, length);
+		}
+	}
+	/** trivial <code>return read (buf, 0, buf.length)</code>
+	 */
+	public int read(byte[] buf) throws IOException {
+		return read(buf, 0, buf.length);
+	}
+	/** Read the next segment of metadata.  The stream <b>must</b>
+	    be right on the segment, ie, the next byte to read is
+	    the metadata block count.  The metadata is parsed and
+	    new tags are added with addTag(), which fires events
+	 */
+	protected void readMetadata() throws IOException {
+		int blockCount = super.read();
+		if (DEBUG) System.out.println("BLOCKCOUNT:"+blockCount);
+		// System.out.println ("blocks to read: " + blockCount);
+		int byteCount = (blockCount * 16); // 16 bytes per block
+		if (byteCount < 0)
+			return; // WTF?!
+		byte[] metadataBlock = new byte[byteCount];
+		int index = 0;
+		// build an array of this metadata
+		while (byteCount > 0) {
+			int bytesRead = super.read(metadataBlock, index, byteCount);
+			index += bytesRead;
+			byteCount -= bytesRead;
+		}
+		// now parse it
+		if (blockCount > 0)
+			parseInlineIcyTags(metadataBlock);
+	} // readMetadata
+	/** Parse metadata from an in-stream "block" of bytes, add
+	    a tag for each one.
+	    <p>
+	    Hilariously, the inline data format is totally different
+	    than the top-of-stream header.  For example, here's a
+	    block I saw on "Final Fantasy Radio":
+	<pre>
+	StreamTitle='Final Fantasy 8 - Nobuo Uematsu - Blue Fields';StreamUrl='';
+	</pre>
+	    In other words:
+	    <ol>
+	    <li>Tags are delimited by semicolons
+	    <li>Keys/values are delimited by equals-signs
+	    <li>Values are wrapped in single-quotes
+	    <li>Key names are in SentenceCase, not lowercase-dashed
+	    </ol>
+	 */
+	protected void parseInlineIcyTags(byte[] tagBlock)
+    {
+		String blockString = null;
+        try
+        {
+            // Parse string as ISO-8859-1 even if meta-data are in US-ASCII.
+            blockString = new String(tagBlock,"ISO-8859-1");
+        }
+        catch(UnsupportedEncodingException e)
+        {
+            blockString = new String(tagBlock);
+        }
+		if (DEBUG) System.out.println("BLOCKSTR:"+blockString);
+		StringTokenizer izer =
+			new StringTokenizer(blockString, INLINE_TAG_SEPARATORS);
+		int i = 0;
+		while (izer.hasMoreTokens()) {
+			String tagString = izer.nextToken();
+			int separatorIdx = tagString.indexOf('=');
+			if (separatorIdx == -1)
+				continue; // bogus tagString if no '='
+			// try to strip single-quotes around value, if present
+			int valueStartIdx =
+				(tagString.charAt(separatorIdx + 1) == '\'')
+					? separatorIdx + 2
+					: separatorIdx + 1;
+			int valueEndIdx =
+				(tagString.charAt(tagString.length() - 1)) == '\''
+					? tagString.length() - 1
+					: tagString.length();
+			String name = tagString.substring(0, separatorIdx);
+			String value = tagString.substring(valueStartIdx, valueEndIdx);
+			// System.out.println (i++ + " " +  name + ":" + value);
+			IcyTag tag = new IcyTag(name, value);
+			addTag(tag);
+		}
+	}
+	/** adds the tag to the HashMap of tags we have encountered
+	    either in-stream or as headers, replacing any previous
+	    tag with this name.
+	 */
+	protected void addTag(IcyTag tag) {
+		tags.put(tag.getName(), tag);
+		// fire this as an event too
+		tagParseSupport.fireTagParsed(this, tag);
+	}
+	/** Get the named tag from the HashMap of headers and
+	    in-line tags.  Null if no such tag has been encountered.
+	 */
+	public MP3Tag getTag(String tagName) {
+		return (MP3Tag) tags.get(tagName);
+	}
+	/** Get all tags (headers or in-stream) encountered thus far.
+	 */
+	public MP3Tag[] getTags() {
+		return (MP3Tag[]) tags.values().toArray(new MP3Tag[0]);
+	}
+	/** Returns a HashMap of all headers and in-stream tags
+	    parsed so far.
+	 */
+	public HashMap getTagHash() {
+		return tags;
+	}
+	/** Adds a TagParseListener to be notified when this stream
+	    parses MP3Tags.
+	 */
+	public void addTagParseListener(TagParseListener tpl) {
+		tagParseSupport.addTagParseListener(tpl);
+	}
+	/** Removes a TagParseListener, so it won't be notified when
+	    this stream parses MP3Tags.
+	 */
+	public void removeTagParseListener(TagParseListener tpl) {
+		tagParseSupport.removeTagParseListener(tpl);
+	}
+	/** Quickie unit-test.
+	 */
+	public static void main(String args[]) {
+		byte[] chow = new byte[200];
+		if (args.length != 1) {
+			//System.out.println("Usage: IcyInputStream <url>");
+			return;
+		}
+		try {
+			URL url = new URL(args[0]);
+			URLConnection conn = url.openConnection();
+			conn.setRequestProperty("Icy-Metadata", "1");
+			IcyInputStream icy =
+				new IcyInputStream(
+					new BufferedInputStream(conn.getInputStream()));
+			while (icy.available() > -1) {
+				// icy.read();
+				icy.read(chow, 0, chow.length);
+			}
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+}

+ 42 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/IcyTag.java

@@ -0,0 +1,42 @@
+/*
+ * IcyTag.
+ * 
+ * jicyshout : http://sourceforge.net/projects/jicyshout/
+ *  
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ * 
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+
+package javazoom.spi.mpeg.sampled.file.tag;
+/** 
+ * A tag parsed from an icecast tag. 
+ */
+public class IcyTag extends MP3Tag implements StringableTag {
+	/** Create a new tag, from the parsed name and (String) value.
+	    It looks like all Icecast tags are Strings (safe to assume
+	    this going forward?)
+	 */
+	public IcyTag(String name, String stringValue) {
+		super(name, stringValue);
+	}
+	// so far as I know, all Icecast tags are strings
+	public String getValueAsString() {
+		return (String) getValue();
+	}
+}

+ 50 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/MP3MetadataParser.java

@@ -0,0 +1,50 @@
+/*
+ * MP3MetadataParser.
+ * 
+ * jicyshout : http://sourceforge.net/projects/jicyshout/
+ *  
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ * 
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+
+package javazoom.spi.mpeg.sampled.file.tag;
+
+/** An object that fires off TagParseEvents as they are parsed
+    from a stream, ServerSocket, or other metadata source
+  */
+public interface MP3MetadataParser {
+	/** Adds a TagParseListener to be notified when this object
+	    parses MP3Tags.
+	 */
+	public void addTagParseListener(TagParseListener tpl);
+	/** Removes a TagParseListener, so it won't be notified when
+	    this object parses MP3Tags.
+	 */
+	public void removeTagParseListener(TagParseListener tpl);
+	/** Get all tags (headers or in-stream) encountered thusfar.
+	    This is included in this otherwise Listener-like scheme
+	    because most standards are a mix of start-of-stream
+	    metadata tags (like the http headers or the stuff at the
+	    top of an ice stream) and inline data.  Implementations should
+	    hang onto all tags they parse and provide them with this
+	    call.  Callers should first use this call to get initial
+	    tags, then subscribe for events as the stream continues.
+	 */
+	public MP3Tag[] getTags();
+}

+ 52 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/MP3Tag.java

@@ -0,0 +1,52 @@
+/*
+ * MP3Tag.
+ * 
+ * jicyshout : http://sourceforge.net/projects/jicyshout/
+ *  
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ * 
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+
+package javazoom.spi.mpeg.sampled.file.tag;
+
+/** An individual piece of mp3 metadata, as a name/value pair.
+    Abstract just so that subclasses will indicate their
+    tagging scheme (Icy, ID3, etc.).
+ */
+public abstract class MP3Tag extends Object {
+	protected String name;
+	protected Object value;
+	public MP3Tag(String name, Object value) {
+		this.name = name;
+		this.value = value;
+	}
+	public String getName() {
+		return name;
+	}
+	public Object getValue() {
+		return value;
+	}
+	public String toString() {
+		return getClass().getName()
+			+ " -- "
+			+ getName()
+			+ ":"
+			+ getValue().toString();
+	}
+}

+ 62 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/MP3TagParseSupport.java

@@ -0,0 +1,62 @@
+/*
+ * MP3TagParseSupport.
+ * 
+ * jicyshout : http://sourceforge.net/projects/jicyshout/
+ *  
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ * 
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+
+package javazoom.spi.mpeg.sampled.file.tag;
+
+import java.util.ArrayList;
+/**  
+*/
+public class MP3TagParseSupport extends Object {
+	ArrayList tagParseListeners;
+	/** trivial constructor, sets up listeners list.
+	 */
+	public MP3TagParseSupport() {
+		super();
+		tagParseListeners = new ArrayList();
+	}
+	/** Adds a TagParseListener to be notified when a stream
+	    parses MP3Tags.
+	 */
+	public void addTagParseListener(TagParseListener tpl) {
+		tagParseListeners.add(tpl);
+	}
+	/** Removes a TagParseListener, so it won't be notified when
+	    a stream parses MP3Tags.
+	 */
+	public void removeTagParseListener(TagParseListener tpl) {
+		tagParseListeners.add(tpl);
+	}
+	/** Fires the given event to all registered listeners
+	 */
+	public void fireTagParseEvent(TagParseEvent tpe) {
+		for (int i = 0; i < tagParseListeners.size(); i++) {
+			TagParseListener l = (TagParseListener) tagParseListeners.get(i);
+			l.tagParsed(tpe);
+		}
+	}
+	public void fireTagParsed(Object source, MP3Tag tag) {
+		fireTagParseEvent(new TagParseEvent(source, tag));
+	}
+}

+ 36 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/StringableTag.java

@@ -0,0 +1,36 @@
+/*
+ * StringableTag.
+ * 
+ * jicyshout : http://sourceforge.net/projects/jicyshout/
+ *  
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ * 
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+
+package javazoom.spi.mpeg.sampled.file.tag;
+
+/** Indicates that the value of a tag is a string, and
+    provides a getValueAsString() method to get it.
+    Appropriate for tags like artist, title, etc.
+ */
+public interface StringableTag {
+	/** Return the value of this tag as a string.
+	 */
+	public String getValueAsString();
+}

+ 44 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/TagParseEvent.java

@@ -0,0 +1,44 @@
+/*
+ * TagParseEvent.
+ * 
+ * jicyshout : http://sourceforge.net/projects/jicyshout/
+ *  
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ * 
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+
+package javazoom.spi.mpeg.sampled.file.tag;
+
+import java.util.EventObject;
+/** Event to indicate that an MP3 tag was received through
+    some means (parsed in stream, received via UDP, whatever)
+    and converted into an MP3Tag object.
+ */
+public class TagParseEvent extends EventObject {
+	protected MP3Tag tag;
+	public TagParseEvent(Object source, MP3Tag tag) {
+		super(source);
+		this.tag = tag;
+	}
+	/** Get the tag that was parsed.
+	 */
+	public MP3Tag getTag() {
+		return tag;
+	}
+}

+ 37 - 0
ToolKit/libs/Mp3Utils/src/javazoom/spi/mpeg/sampled/file/tag/TagParseListener.java

@@ -0,0 +1,37 @@
+/*
+ * TagParseListener.
+ * 
+ * jicyshout : http://sourceforge.net/projects/jicyshout/
+ *  
+ * JavaZOOM : mp3spi@javazoom.net
+ * 			  http://www.javazoom.net
+ * 
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+
+package javazoom.spi.mpeg.sampled.file.tag;
+
+import java.util.EventListener;
+/** EventListener to be implemented by objects that want to
+    get callbacks when MP3 tags are received.
+ */
+public interface TagParseListener extends EventListener {
+	/** Called when a tag is found (parsed from the stream,
+	    received via UDP, etc.)
+	 */
+	public void tagParsed(TagParseEvent tpe);
+}

BIN
ToolKit/libs/Mp3Utils/tritonus_share.jar


BIN
ToolKit/libs/OggUtils/jogg-0.0.7.jar


BIN
ToolKit/libs/OggUtils/jorbis-0.0.15.jar


+ 2 - 0
ToolKit/libs/OggUtils/src/META-INF/services/javax.sound.sampled.spi.AudioFileReader

@@ -0,0 +1,2 @@
+# for the vorbis decoder
+javazoom.spi.vorbis.sampled.file.VorbisAudioFileReader

+ 2 - 0
ToolKit/libs/OggUtils/src/META-INF/services/javax.sound.sampled.spi.FormatConversionProvider

@@ -0,0 +1,2 @@
+# for the vorbis decoder
+javazoom.spi.vorbis.sampled.convert.VorbisFormatConversionProvider

+ 31 - 0
ToolKit/libs/OggUtils/src/javazoom/spi/PropertiesContainer.java

@@ -0,0 +1,31 @@
+/*
+ * PropertiesContainer.
+ * 
+ * JavaZOOM : vorbisspi@javazoom.net
+ * 			  http://www.javazoom.net
+ * 
+ *-----------------------------------------------------------------------
+ *   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.
+ *----------------------------------------------------------------------
+ */
+
+package javazoom.spi;
+
+import java.util.Map;
+
+public interface PropertiesContainer
+{
+	public Map properties();
+}

+ 519 - 0
ToolKit/libs/OggUtils/src/javazoom/spi/vorbis/sampled/convert/DecodedVorbisAudioInputStream.java

@@ -0,0 +1,519 @@
+/*
+ *   DecodedVorbisAudioInputStream
+ *   
+ *    JavaZOOM : vorbisspi@javazoom.net
+ *               http://www.javazoom.net
+ *
+ * ----------------------------------------------------------------------------
+ *   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.
+ * ----------------------------------------------------------------------------
+ */
+ 
+package javazoom.spi.vorbis.sampled.convert;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+
+import javazoom.spi.PropertiesContainer;
+
+import org.tritonus.share.TDebug;
+import org.tritonus.share.sampled.convert.TAsynchronousFilteredAudioInputStream;
+
+import com.jcraft.jogg.Packet;
+import com.jcraft.jogg.Page;
+import com.jcraft.jogg.StreamState;
+import com.jcraft.jogg.SyncState;
+import com.jcraft.jorbis.Block;
+import com.jcraft.jorbis.Comment;
+import com.jcraft.jorbis.DspState;
+import com.jcraft.jorbis.Info;
+
+/**
+ * This class implements the Vorbis decoding.
+ */
+public class DecodedVorbisAudioInputStream extends TAsynchronousFilteredAudioInputStream implements PropertiesContainer
+{
+  private InputStream oggBitStream_ = null;
+
+  private SyncState oggSyncState_ = null;
+  private StreamState oggStreamState_ = null;
+  private Page oggPage_ = null;
+  private Packet oggPacket_ = null;
+  private Info vorbisInfo = null;
+  private Comment vorbisComment = null;
+  private DspState vorbisDspState = null;
+  private Block vorbisBlock = null;
+
+  static final int playState_NeedHeaders = 0;
+  static final int playState_ReadData = 1;
+  static final int playState_WriteData = 2;
+  static final int playState_Done = 3;
+  static final int playState_BufferFull = 4;
+  static final int playState_Corrupt = -1;
+  private int playState;
+
+  private int bufferMultiple_ = 4;
+  private int bufferSize_ = bufferMultiple_ * 256 * 2;
+  private int convsize = bufferSize_ * 2;
+  private byte[] convbuffer = new byte[convsize];
+  private byte[] buffer = null;
+  private int bytes = 0;
+  private float[][][] _pcmf = null;
+  private int[] _index = null;
+  private int index = 0;
+  private int i = 0;
+  // bout is now a global so that we can continue from when we have a buffer full.
+  int bout = 0;
+  
+  private HashMap properties = null;
+  private long currentBytes = 0;
+
+  /**
+   * Constructor.
+   */
+  public DecodedVorbisAudioInputStream(AudioFormat outputFormat, AudioInputStream bitStream)
+  {
+    super(outputFormat, -1);
+    this.oggBitStream_ = bitStream;
+    init_jorbis();
+    index = 0;
+    playState = playState_NeedHeaders;
+	properties = new HashMap();
+  }
+
+  /**
+   * Initializes all the jOrbis and jOgg vars that are used for song playback.
+   */
+  private void init_jorbis()
+  {
+    oggSyncState_ = new SyncState();
+    oggStreamState_ = new StreamState();
+    oggPage_ = new Page();
+    oggPacket_ = new Packet();
+    vorbisInfo = new Info();
+    vorbisComment = new Comment();
+    vorbisDspState = new DspState();
+    vorbisBlock = new Block(vorbisDspState);
+    buffer = null;
+    bytes = 0;
+	currentBytes = 0L;
+    oggSyncState_.init();
+  }
+
+  /**
+   * Return dynamic properties.
+   * 
+   * <ul>
+   * <li><b>ogg.position.byte</b> [Long], current position in bytes in the stream.
+   *</ul>
+   */
+  public Map properties()
+  {
+	  properties.put("ogg.position.byte",new Long(currentBytes));
+	  return properties;	 
+  }
+  /**
+   * Main loop.
+   */
+  public void execute()
+  {
+    if(TDebug.TraceAudioConverter)
+    {
+      switch(playState)
+      {
+        case playState_NeedHeaders:
+          TDebug.out("playState = playState_NeedHeaders");
+          break;
+        case playState_ReadData:
+          TDebug.out("playState = playState_ReadData");
+          break;
+        case playState_WriteData:
+          TDebug.out("playState = playState_WriteData");
+          break;
+        case playState_Done:
+          TDebug.out("playState = playState_Done");
+          break;
+        case playState_BufferFull:
+          TDebug.out("playState = playState_BufferFull");
+          break;
+        case playState_Corrupt:
+          TDebug.out("playState = playState_Corrupt");
+          break;
+      }
+    }
+    // This code was developed by the jCraft group, as JOrbisPlayer.java,  slightly
+    // modified by jOggPlayer developer and adapted by JavaZOOM to suit the JavaSound
+    // SPI. Then further modified by Tom Kimpton to correctly play ogg files that
+    // would hang the player.
+    switch(playState)
+    {
+      case playState_NeedHeaders:
+        try
+        {
+          // Headers (+ Comments).
+          readHeaders();
+        }
+        catch(IOException ioe)
+        {
+          playState = playState_Corrupt;
+          return;
+        }
+        playState = playState_ReadData;
+        break;
+
+      case playState_ReadData:
+        int result;
+        index = oggSyncState_.buffer(bufferSize_);
+        buffer = oggSyncState_.data;
+        bytes = readFromStream(buffer, index, bufferSize_);
+        if(TDebug.TraceAudioConverter) TDebug.out("More data : " + bytes);
+        if(bytes == -1)
+        {
+          playState = playState_Done;
+          if(TDebug.TraceAudioConverter) TDebug.out("Ogg Stream empty. Settings playState to playState_Done.");
+          break;
+        }
+        else
+        {
+          oggSyncState_.wrote(bytes);
+          if(bytes == 0)
+          {
+            if((oggPage_.eos() != 0) || (oggStreamState_.e_o_s != 0) || (oggPacket_.e_o_s != 0))
+            {
+              if(TDebug.TraceAudioConverter) TDebug.out("oggSyncState wrote 0 bytes: settings playState to playState_Done.");
+              playState = playState_Done;
+            }
+              if(TDebug.TraceAudioConverter) TDebug.out("oggSyncState wrote 0 bytes: but stream not yet empty.");
+            break;
+          }
+        }
+
+        result = oggSyncState_.pageout(oggPage_);
+        if(result == 0)
+        {
+          if(TDebug.TraceAudioConverter) TDebug.out("Setting playState to playState_ReadData.");
+          playState = playState_ReadData;
+          break;
+        } // need more data
+        if(result == -1)
+        { // missing or corrupt data at this page position
+          if(TDebug.TraceAudioConverter) TDebug.out("Corrupt or missing data in bitstream; setting playState to playState_ReadData");
+          playState = playState_ReadData;
+          break;
+        }
+
+        oggStreamState_.pagein(oggPage_);
+
+        if(TDebug.TraceAudioConverter) TDebug.out("Setting playState to playState_WriteData.");
+        playState = playState_WriteData;
+        break;
+
+      case playState_WriteData:
+        // Decoding !
+        if(TDebug.TraceAudioConverter) TDebug.out("Decoding");
+        while(true)
+        {
+          result = oggStreamState_.packetout(oggPacket_);
+          if(result == 0)
+          {
+            if(TDebug.TraceAudioConverter) TDebug.out("Packetout returned 0, going to read state.");
+            playState = playState_ReadData;
+            break;
+          } // need more data
+          else if(result == -1)
+          { 
+          	// missing or corrupt data at this page position
+            // no reason to complain; already complained above
+			if(TDebug.TraceAudioConverter) TDebug.out("Corrupt or missing data in packetout bitstream; going to read state...");
+			// playState = playState_ReadData;
+			// break;
+            continue;
+          }
+          else
+          {
+            // we have a packet.  Decode it
+            if(vorbisBlock.synthesis(oggPacket_) == 0)
+            { // test for success!
+              vorbisDspState.synthesis_blockin(vorbisBlock);
+            }
+            else
+            {
+              //if(TDebug.TraceAudioConverter) TDebug.out("vorbisBlock.synthesis() returned !0, going to read state");
+              if(TDebug.TraceAudioConverter) TDebug.out("VorbisBlock.synthesis() returned !0, continuing.");
+              continue;
+            }
+
+            outputSamples();
+            if(playState == playState_BufferFull)
+              return;
+
+          } // else result != -1
+        } // while(true)
+        if(oggPage_.eos() != 0)
+        {
+          if(TDebug.TraceAudioConverter) TDebug.out("Settings playState to playState_Done.");
+          playState = playState_Done;
+        }
+        break;
+      case playState_BufferFull:
+        continueFromBufferFull();
+        break;
+
+      case playState_Corrupt:
+        if(TDebug.TraceAudioConverter) TDebug.out("Corrupt Song.");
+        // drop through to playState_Done...
+      case playState_Done:
+        oggStreamState_.clear();
+        vorbisBlock.clear();
+        vorbisDspState.clear();
+        vorbisInfo.clear();
+        oggSyncState_.clear();
+        if(TDebug.TraceAudioConverter) TDebug.out("Done Song.");
+        try
+        {
+          if(oggBitStream_ != null)
+          {
+            oggBitStream_.close();
+          }
+          getCircularBuffer().close();
+        }
+        catch(Exception e)
+        {
+          if(TDebug.TraceAudioConverter) TDebug.out(e.getMessage());
+        }
+        break;
+    } // switch
+  }
+
+  /**
+   * This routine was extracted so that when the output buffer fills up,
+   * we can break out of the loop, let the music channel drain, then
+   * continue from where we were.
+   */
+  private void outputSamples()
+  {
+    int samples;
+    while((samples = vorbisDspState.synthesis_pcmout(_pcmf, _index)) > 0)
+    {
+      float[][] pcmf = _pcmf[0];
+      bout = (samples < convsize ? samples : convsize);
+      double fVal = 0.0;
+      // convert doubles to 16 bit signed ints (host order) and
+      // interleave
+      for(i = 0; i < vorbisInfo.channels; i++)
+      {
+        int pointer = i * 2;
+        //int ptr=i;
+        int mono = _index[i];
+        for(int j = 0; j < bout; j++)
+        {
+          fVal = pcmf[i][mono + j] * 32767.;
+          int val = (int) (fVal);
+          if(val > 32767)
+          {
+            val = 32767;
+          }
+          if(val < -32768)
+          {
+            val = -32768;
+          }
+          if(val < 0)
+          {
+            val = val | 0x8000;
+          }
+          convbuffer[pointer] = (byte) (val);
+          convbuffer[pointer + 1] = (byte) (val >>> 8);
+          pointer += 2 * (vorbisInfo.channels);
+        }
+      }
+      if(TDebug.TraceAudioConverter) TDebug.out("about to write: " + 2 * vorbisInfo.channels * bout);
+      if(getCircularBuffer().availableWrite() < 2 * vorbisInfo.channels * bout)
+      {
+        if(TDebug.TraceAudioConverter) TDebug.out("Too much data in this data packet, better return, let the channel drain, and try again...");
+        playState = playState_BufferFull;
+        return;
+      }
+      getCircularBuffer().write(convbuffer, 0, 2 * vorbisInfo.channels * bout);
+      if(bytes < bufferSize_)
+        if(TDebug.TraceAudioConverter) TDebug.out("Finished with final buffer of music?");
+      if(vorbisDspState.synthesis_read(bout) != 0)
+      {
+        if(TDebug.TraceAudioConverter) TDebug.out("VorbisDspState.synthesis_read returned -1.");
+      }
+    } // while(samples...)
+    playState = playState_ReadData;
+  }
+
+  private void continueFromBufferFull()
+  {
+    if(getCircularBuffer().availableWrite() < 2 * vorbisInfo.channels * bout)
+    {
+      if(TDebug.TraceAudioConverter) TDebug.out("Too much data in this data packet, better return, let the channel drain, and try again...");
+      // Don't change play state.
+      return;
+    }
+    getCircularBuffer().write(convbuffer, 0, 2 * vorbisInfo.channels * bout);
+    // Don't change play state. Let outputSamples change play state, if necessary.
+    outputSamples();
+  }
+  /**
+   * Reads headers and comments.
+   */
+  private void readHeaders() throws IOException
+  {
+    if(TDebug.TraceAudioConverter) TDebug.out("readHeaders(");
+    index = oggSyncState_.buffer(bufferSize_);
+    buffer = oggSyncState_.data;
+    bytes = readFromStream(buffer, index, bufferSize_);
+    if(bytes == -1)
+    {
+      if(TDebug.TraceAudioConverter) TDebug.out("Cannot get any data from selected Ogg bitstream.");
+      throw new IOException("Cannot get any data from selected Ogg bitstream.");
+    }
+    oggSyncState_.wrote(bytes);
+    if(oggSyncState_.pageout(oggPage_) != 1)
+    {
+      if(bytes < bufferSize_)
+      {
+        throw new IOException("EOF");
+      }
+      if(TDebug.TraceAudioConverter) TDebug.out("Input does not appear to be an Ogg bitstream.");
+      throw new IOException("Input does not appear to be an Ogg bitstream.");
+    }
+    oggStreamState_.init(oggPage_.serialno());
+    vorbisInfo.init();
+    vorbisComment.init();
+    if(oggStreamState_.pagein(oggPage_) < 0)
+    {
+      // error; stream version mismatch perhaps
+      if(TDebug.TraceAudioConverter) TDebug.out("Error reading first page of Ogg bitstream data.");
+      throw new IOException("Error reading first page of Ogg bitstream data.");
+    }
+    if(oggStreamState_.packetout(oggPacket_) != 1)
+    {
+      // no page? must not be vorbis
+      if(TDebug.TraceAudioConverter) TDebug.out("Error reading initial header packet.");
+      throw new IOException("Error reading initial header packet.");
+    }
+    if(vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_) < 0)
+    {
+      // error case; not a vorbis header
+      if(TDebug.TraceAudioConverter) TDebug.out("This Ogg bitstream does not contain Vorbis audio data.");
+      throw new IOException("This Ogg bitstream does not contain Vorbis audio data.");
+    }
+    //int i = 0;
+    i = 0;
+    while(i < 2)
+    {
+      while(i < 2)
+      {
+        int result = oggSyncState_.pageout(oggPage_);
+        if(result == 0)
+        {
+          break;
+        } // Need more data
+        if(result == 1)
+        {
+          oggStreamState_.pagein(oggPage_);
+          while(i < 2)
+          {
+            result = oggStreamState_.packetout(oggPacket_);
+            if(result == 0)
+            {
+              break;
+            }
+            if(result == -1)
+            {
+              if(TDebug.TraceAudioConverter) TDebug.out("Corrupt secondary header.  Exiting.");
+              throw new IOException("Corrupt secondary header.  Exiting.");
+            }
+            vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_);
+            i++;
+          }
+        }
+      }
+      index = oggSyncState_.buffer(bufferSize_);
+      buffer = oggSyncState_.data;
+      bytes = readFromStream(buffer, index, bufferSize_);
+      if(bytes == -1)
+      {
+        break;
+      }
+      if(bytes == 0 && i < 2)
+      {
+        if(TDebug.TraceAudioConverter) TDebug.out("End of file before finding all Vorbis headers!");
+        throw new IOException("End of file before finding all Vorbis  headers!");
+      }
+      oggSyncState_.wrote(bytes);
+    }
+
+    byte[][] ptr = vorbisComment.user_comments;
+    String currComment = "";
+
+    for(int j = 0; j < ptr.length; j++)
+    {
+      if(ptr[j] == null)
+      {
+        break;
+      }
+      currComment = (new String(ptr[j], 0, ptr[j].length - 1)).trim();
+      if(TDebug.TraceAudioConverter) TDebug.out("Comment: " + currComment);
+    }
+    convsize = bufferSize_ / vorbisInfo.channels;
+    vorbisDspState.synthesis_init(vorbisInfo);
+    vorbisBlock.init(vorbisDspState);
+    _pcmf = new float[1][][];
+    _index = new int[vorbisInfo.channels];
+  }
+
+  /**
+   * Reads from the oggBitStream_ a specified number of Bytes(bufferSize_) worth
+   * starting at index and puts them in the specified buffer[].
+   *
+   * @param buffer
+   * @param index
+   * @param bufferSize_
+   * @return             the number of bytes read or -1 if error.
+   */
+  private int readFromStream(byte[] buffer, int index, int bufferSize_)
+  {
+    int bytes = 0;
+    try
+    {
+      bytes = oggBitStream_.read(buffer, index, bufferSize_);
+    }
+    catch(Exception e)
+    {
+      if(TDebug.TraceAudioConverter) TDebug.out("Cannot Read Selected Song");
+      bytes = -1;
+    }
+    currentBytes = currentBytes + bytes;
+    return bytes;
+  }
+
+  /**
+   * Close the stream.
+   */
+  public void close() throws IOException
+  {
+    super.close();
+    oggBitStream_.close();
+  }
+}

+ 244 - 0
ToolKit/libs/OggUtils/src/javazoom/spi/vorbis/sampled/convert/VorbisFormatConversionProvider.java

@@ -0,0 +1,244 @@
+/*
+ *   VorbisFormatConversionProvider.
+ * 
+ *   JavaZOOM : vorbisspi@javazoom.net
+ *              http://www.javazoom.net
+ *
+ *   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.
+ *
+ */
+ 
+package javazoom.spi.vorbis.sampled.convert;
+
+import java.util.Arrays;
+import javazoom.spi.vorbis.sampled.file.VorbisEncoding;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+
+import org.tritonus.share.sampled.convert.TMatrixFormatConversionProvider;
+
+/**
+ * ConversionProvider for VORBIS files.
+ */
+public class VorbisFormatConversionProvider extends TMatrixFormatConversionProvider
+{
+  private static final AudioFormat[] INPUT_FORMATS =
+  {
+      new AudioFormat(VorbisEncoding.VORBISENC, 32000.0F, -1, 1, -1, -1, false), // 0
+      new AudioFormat(VorbisEncoding.VORBISENC, 32000.0F, -1, 2, -1, -1, false), // 1
+      new AudioFormat(VorbisEncoding.VORBISENC, 44100.0F, -1, 1, -1, -1, false), // 2
+      new AudioFormat(VorbisEncoding.VORBISENC, 44100.0F, -1, 2, -1, -1, false), // 3
+      new AudioFormat(VorbisEncoding.VORBISENC, 48000.0F, -1, 1, -1, -1, false), // 4
+      new AudioFormat(VorbisEncoding.VORBISENC, 48000.0F, -1, 2, -1, -1, false), // 5
+
+      new AudioFormat(VorbisEncoding.VORBISENC, 16000.0F, -1, 1, -1, -1, false), // 18
+      new AudioFormat(VorbisEncoding.VORBISENC, 16000.0F, -1, 2, -1, -1, false), // 19
+      new AudioFormat(VorbisEncoding.VORBISENC, 22050.0F, -1, 1, -1, -1, false), // 20
+      new AudioFormat(VorbisEncoding.VORBISENC, 22050.0F, -1, 2, -1, -1, false), // 21
+      new AudioFormat(VorbisEncoding.VORBISENC, 24000.0F, -1, 1, -1, -1, false), // 22
+      new AudioFormat(VorbisEncoding.VORBISENC, 24000.0F, -1, 2, -1, -1, false), // 23
+
+      new AudioFormat(VorbisEncoding.VORBISENC, 8000.0F, -1, 1, -1, -1, false), // 36
+      new AudioFormat(VorbisEncoding.VORBISENC, 8000.0F, -1, 2, -1, -1, false), // 37
+      new AudioFormat(VorbisEncoding.VORBISENC, 11025.0F, -1, 1, -1, -1, false), // 38
+      new AudioFormat(VorbisEncoding.VORBISENC, 11025.0F, -1, 2, -1, -1, false), // 39
+      new AudioFormat(VorbisEncoding.VORBISENC, 12000.0F, -1, 1, -1, -1, false), // 40
+      new AudioFormat(VorbisEncoding.VORBISENC, 12000.0F, -1, 2, -1, -1, false), // 41
+  };
+
+  private static final AudioFormat[] OUTPUT_FORMATS =
+  {
+      new AudioFormat(8000.0F, 16, 1, true, false), // 0
+      new AudioFormat(8000.0F, 16, 1, true, true), // 1
+      new AudioFormat(8000.0F, 16, 2, true, false), // 2
+      new AudioFormat(8000.0F, 16, 2, true, true), // 3
+      /*	24 and 32 bit not yet possible
+                      new AudioFormat(8000.0F, 24, 1, true, false),
+                      new AudioFormat(8000.0F, 24, 1, true, true),
+                      new AudioFormat(8000.0F, 24, 2, true, false),
+                      new AudioFormat(8000.0F, 24, 2, true, true),
+                      new AudioFormat(8000.0F, 32, 1, true, false),
+                      new AudioFormat(8000.0F, 32, 1, true, true),
+                      new AudioFormat(8000.0F, 32, 2, true, false),
+                      new AudioFormat(8000.0F, 32, 2, true, true),
+       */
+      new AudioFormat(11025.0F, 16, 1, true, false), // 4
+      new AudioFormat(11025.0F, 16, 1, true, true), // 5
+      new AudioFormat(11025.0F, 16, 2, true, false), // 6
+      new AudioFormat(11025.0F, 16, 2, true, true), // 7
+      /*	24 and 32 bit not yet possible
+                      new AudioFormat(11025.0F, 24, 1, true, false),
+                      new AudioFormat(11025.0F, 24, 1, true, true),
+                      new AudioFormat(11025.0F, 24, 2, true, false),
+                      new AudioFormat(11025.0F, 24, 2, true, true),
+                      new AudioFormat(11025.0F, 32, 1, true, false),
+                      new AudioFormat(11025.0F, 32, 1, true, true),
+                      new AudioFormat(11025.0F, 32, 2, true, false),
+                      new AudioFormat(11025.0F, 32, 2, true, true),
+       */
+      new AudioFormat(12000.0F, 16, 1, true, false), // 8
+      new AudioFormat(12000.0F, 16, 1, true, true), // 9
+      new AudioFormat(12000.0F, 16, 2, true, false), // 10
+      new AudioFormat(12000.0F, 16, 2, true, true), // 11
+      /*	24 and 32 bit not yet possible
+                      new AudioFormat(12000.0F, 24, 1, true, false),
+                      new AudioFormat(12000.0F, 24, 1, true, true),
+                      new AudioFormat(12000.0F, 24, 2, true, false),
+                      new AudioFormat(12000.0F, 24, 2, true, true),
+                      new AudioFormat(12000.0F, 32, 1, true, false),
+                      new AudioFormat(12000.0F, 32, 1, true, true),
+                      new AudioFormat(12000.0F, 32, 2, true, false),
+                      new AudioFormat(12000.0F, 32, 2, true, true),
+       */
+      new AudioFormat(16000.0F, 16, 1, true, false), // 12
+      new AudioFormat(16000.0F, 16, 1, true, true), // 13
+      new AudioFormat(16000.0F, 16, 2, true, false), // 14
+      new AudioFormat(16000.0F, 16, 2, true, true), // 15
+      /*	24 and 32 bit not yet possible
+                      new AudioFormat(16000.0F, 24, 1, true, false),
+                      new AudioFormat(16000.0F, 24, 1, true, true),
+                      new AudioFormat(16000.0F, 24, 2, true, false),
+                      new AudioFormat(16000.0F, 24, 2, true, true),
+                      new AudioFormat(16000.0F, 32, 1, true, false),
+                      new AudioFormat(16000.0F, 32, 1, true, true),
+                      new AudioFormat(16000.0F, 32, 2, true, false),
+                      new AudioFormat(16000.0F, 32, 2, true, true),
+       */
+      new AudioFormat(22050.0F, 16, 1, true, false), // 16
+      new AudioFormat(22050.0F, 16, 1, true, true), // 17
+      new AudioFormat(22050.0F, 16, 2, true, false), // 18
+      new AudioFormat(22050.0F, 16, 2, true, true), // 19
+      /*	24 and 32 bit not yet possible
+                      new AudioFormat(22050.0F, 24, 1, true, false),
+                      new AudioFormat(22050.0F, 24, 1, true, true),
+                      new AudioFormat(22050.0F, 24, 2, true, false),
+                      new AudioFormat(22050.0F, 24, 2, true, true),
+                      new AudioFormat(22050.0F, 32, 1, true, false),
+                      new AudioFormat(22050.0F, 32, 1, true, true),
+                      new AudioFormat(22050.0F, 32, 2, true, false),
+                      new AudioFormat(22050.0F, 32, 2, true, true),
+       */
+      new AudioFormat(24000.0F, 16, 1, true, false), // 20
+      new AudioFormat(24000.0F, 16, 1, true, true), // 21
+      new AudioFormat(24000.0F, 16, 2, true, false), // 22
+      new AudioFormat(24000.0F, 16, 2, true, true), // 23
+      /*	24 and 32 bit not yet possible
+                      new AudioFormat(24000.0F, 24, 1, true, false),
+                      new AudioFormat(24000.0F, 24, 1, true, true),
+                      new AudioFormat(24000.0F, 24, 2, true, false),
+                      new AudioFormat(24000.0F, 24, 2, true, true),
+                      new AudioFormat(24000.0F, 32, 1, true, false),
+                      new AudioFormat(24000.0F, 32, 1, true, true),
+                      new AudioFormat(24000.0F, 32, 2, true, false),
+                      new AudioFormat(24000.0F, 32, 2, true, true),
+       */
+      new AudioFormat(32000.0F, 16, 1, true, false), // 24
+      new AudioFormat(32000.0F, 16, 1, true, true), // 25
+      new AudioFormat(32000.0F, 16, 2, true, false), // 26
+      new AudioFormat(32000.0F, 16, 2, true, true), // 27
+      /*	24 and 32 bit not yet possible
+                      new AudioFormat(32000.0F, 24, 1, true, false),
+                      new AudioFormat(32000.0F, 24, 1, true, true),
+                      new AudioFormat(32000.0F, 24, 2, true, false),
+                      new AudioFormat(32000.0F, 24, 2, true, true),
+                      new AudioFormat(32000.0F, 32, 1, true, false),
+                      new AudioFormat(32000.0F, 32, 1, true, true),
+                      new AudioFormat(32000.0F, 32, 2, true, false),
+                      new AudioFormat(32000.0F, 32, 2, true, true),
+       */
+      new AudioFormat(44100.0F, 16, 1, true, false), // 28
+      new AudioFormat(44100.0F, 16, 1, true, true), // 29
+      new AudioFormat(44100.0F, 16, 2, true, false), // 30
+      new AudioFormat(44100.0F, 16, 2, true, true), // 31
+      /*	24 and 32 bit not yet possible
+                      new AudioFormat(44100.0F, 24, 1, true, false),
+                      new AudioFormat(44100.0F, 24, 1, true, true),
+                      new AudioFormat(44100.0F, 24, 2, true, false),
+                      new AudioFormat(44100.0F, 24, 2, true, true),
+                      new AudioFormat(44100.0F, 32, 1, true, false),
+                      new AudioFormat(44100.0F, 32, 1, true, true),
+                      new AudioFormat(44100.0F, 32, 2, true, false),
+                      new AudioFormat(44100.0F, 32, 2, true, true),
+       */
+      new AudioFormat(48000.0F, 16, 1, true, false), // 32
+      new AudioFormat(48000.0F, 16, 1, true, true), // 33
+      new AudioFormat(48000.0F, 16, 2, true, false), // 34
+      new AudioFormat(48000.0F, 16, 2, true, true), // 35
+      /*	24 and 32 bit not yet possible
+                      new AudioFormat(48000.0F, 24, 1, true, false),
+                      new AudioFormat(48000.0F, 24, 1, true, true),
+                      new AudioFormat(48000.0F, 24, 2, true, false),
+                      new AudioFormat(48000.0F, 24, 2, true, true),
+                      new AudioFormat(48000.0F, 32, 1, true, false),
+                      new AudioFormat(48000.0F, 32, 1, true, true),
+                      new AudioFormat(48000.0F, 32, 2, true, false),
+                      new AudioFormat(48000.0F, 32, 2, true, true),
+       */
+  };
+
+  private static final boolean t = true;
+  private static final boolean f = false;
+
+  /*
+   *	One row for each source format.
+   */
+  private static final boolean[][] CONVERSIONS =
+  {
+      {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,t,t,f,f,f,f, f,f,f,f,f,f},	// 0
+      {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,t,t,f,f, f,f,f,f,f,f},	// 1
+      {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,t,t, f,f,f,f,f,f},	// 2
+      {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, t,t,f,f,f,f},	// 3
+      {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,t,t,f,f},	// 4
+      {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,t,t},	// 5
+
+      {f,f,f,f,f,f,f,f,f,f, f,f,t,t,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f},	// 18
+      {f,f,f,f,f,f,f,f,f,f, f,f,f,f,t,t,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f},	// 19
+      {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,t,t,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f},	// 20
+      {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,t,t, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f},	// 21
+      {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, t,t,f,f,f,f,f,f,f,f, f,f,f,f,f,f},	// 22
+      {f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,t,t,f,f,f,f,f,f, f,f,f,f,f,f},	// 23
+
+      {t,t,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f},	// 36
+      {f,f,t,t,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f},	// 37
+      {f,f,f,f,t,t,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f},	// 38
+      {f,f,f,f,f,f,t,t,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f},	// 39
+      {f,f,f,f,f,f,f,f,t,t, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f},	// 40
+      {f,f,f,f,f,f,f,f,f,f, t,t,f,f,f,f,f,f,f,f, f,f,f,f,f,f,f,f,f,f, f,f,f,f,f,f},	// 41
+
+  };
+
+  /**
+   * Constructor.
+   */
+  public VorbisFormatConversionProvider()
+  {
+    super(Arrays.asList(INPUT_FORMATS), Arrays.asList(OUTPUT_FORMATS), CONVERSIONS);
+  }
+
+  /**
+   * Returns converted AudioInputStream.
+   */
+  public AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream audioInputStream)
+  {
+    if (isConversionSupported(targetFormat, audioInputStream.getFormat()))
+    {
+      return new DecodedVorbisAudioInputStream(targetFormat, audioInputStream);
+    }
+    else
+    {
+      throw new IllegalArgumentException("conversion not supported");
+    }
+  }
+}

+ 85 - 0
ToolKit/libs/OggUtils/src/javazoom/spi/vorbis/sampled/file/VorbisAudioFileFormat.java

@@ -0,0 +1,85 @@
+/*
+ *   VorbisAudioFileFormat.
+ * 
+ *   JavaZOOM : vorbisspi@javazoom.net
+ *              http://www.javazoom.net 
+ *
+ *   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.
+ *
+ */
+
+package javazoom.spi.vorbis.sampled.file;
+
+import java.util.Map;
+
+import javax.sound.sampled.AudioFormat;
+
+import org.tritonus.share.sampled.file.TAudioFileFormat;
+
+/**
+ * @author JavaZOOM
+ */
+public class VorbisAudioFileFormat extends TAudioFileFormat
+{
+	/**
+	 * Contructor. 
+	 * @param type
+	 * @param audioFormat
+	 * @param nLengthInFrames
+	 * @param nLengthInBytes
+	 */
+	public VorbisAudioFileFormat(Type type, AudioFormat audioFormat, int nLengthInFrames, int nLengthInBytes, Map properties)
+	{
+		super(type, audioFormat, nLengthInFrames, nLengthInBytes, properties);
+	}
+
+	/**
+	 * Ogg Vorbis audio file format parameters. 
+	 * Some parameters might be unavailable. So availability test is required before reading any parameter.  
+	 *
+	 * <br>AudioFileFormat parameters.
+	 * <ul>
+	 * <li><b>duration</b> [Long], duration in microseconds.
+	 * <li><b>title</b> [String], Title of the stream.
+	 * <li><b>author</b> [String], Name of the artist of the stream.
+	 * <li><b>album</b> [String], Name of the album of the stream.
+	 * <li><b>date</b> [String], The date (year) of the recording or release of the stream.
+	 * <li><b>copyright</b> [String], Copyright message of the stream.
+	 * <li><b>comment</b> [String], Comment of the stream.
+	 * </ul>
+	 * <br>Ogg Vorbis parameters.
+	 * <ul>
+	 * <li><b>ogg.length.bytes</b> [Integer], length in bytes.
+	 * <li><b>ogg.bitrate.min.bps</b> [Integer], minimum bitrate.
+	 * <li><b>ogg.bitrate.nominal.bps</b> [Integer], nominal bitrate.
+	 * <li><b>ogg.bitrate.max.bps</b> [Integer], maximum bitrate.
+	 * <li><b>ogg.channels</b> [Integer], number of channels 1 : mono, 2 : stereo.
+	 * <li><b>ogg.frequency.hz</b> [Integer], sampling rate in hz.
+	 * <li><b>ogg.version</b> [Integer], version.
+	 * <li><b>ogg.serial</b> [Integer], serial number. 
+	 * <li><b>ogg.comment.track</b> [String], track number.
+	 * <li><b>ogg.comment.genre</b> [String], genre field.
+	 * <li><b>ogg.comment.encodedby</b> [String], encoded by field.
+	 * <li><b>ogg.comment.ext</b> [String], extended comments (indexed):
+	 * <br>For instance : 
+	 * <br>ogg.comment.ext.1=Something
+	 * <br>ogg.comment.ext.2=Another comment 
+	 * </ul>
+	 */
+	public Map properties()
+	{
+		return super.properties();	
+	}	
+}

+ 508 - 0
ToolKit/libs/OggUtils/src/javazoom/spi/vorbis/sampled/file/VorbisAudioFileReader.java

@@ -0,0 +1,508 @@
+/*
+ *   VorbisAudioFileReader.
+ * 
+ *   JavaZOOM : vorbisspi@javazoom.net
+ *              http://www.javazoom.net 
+ *
+ *   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.
+ *
+ */
+ 
+package javazoom.spi.vorbis.sampled.file;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+
+import javax.sound.sampled.AudioFileFormat;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+import org.tritonus.share.TDebug;
+import org.tritonus.share.sampled.file.TAudioFileReader;
+
+import com.jcraft.jogg.Packet;
+import com.jcraft.jogg.Page;
+import com.jcraft.jogg.StreamState;
+import com.jcraft.jogg.SyncState;
+import com.jcraft.jorbis.Block;
+import com.jcraft.jorbis.Comment;
+import com.jcraft.jorbis.DspState;
+import com.jcraft.jorbis.Info;
+import com.jcraft.jorbis.JOrbisException;
+import com.jcraft.jorbis.VorbisFile;
+
+/**
+ * This class implements the AudioFileReader class and provides an
+ * Ogg Vorbis file reader for use with the Java Sound Service Provider Interface.
+ */
+public class VorbisAudioFileReader extends TAudioFileReader
+{
+  private SyncState oggSyncState_ = null;
+  private StreamState oggStreamState_ = null;
+  private Page oggPage_ = null;
+  private Packet oggPacket_ = null;
+  private Info vorbisInfo = null;
+  private Comment vorbisComment = null;
+  private DspState vorbisDspState = null;
+  private Block vorbisBlock = null;
+  private int bufferMultiple_ = 4;
+  private int bufferSize_ = bufferMultiple_ * 256 * 2;
+  private byte[] buffer = null;
+  private int bytes = 0;
+
+  private int index = 0;
+  private InputStream oggBitStream_ = null;
+
+  private static final int	INITAL_READ_LENGTH = 64000;
+  private static final int	MARK_LIMIT = INITAL_READ_LENGTH + 1;
+  
+  public VorbisAudioFileReader()
+  {
+	  super(MARK_LIMIT, true);
+  }
+
+  /**
+   * Return the AudioFileFormat from the given file.
+   */
+  public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException
+  {
+	if (TDebug.TraceAudioFileReader) TDebug.out("getAudioFileFormat(File file)");
+    InputStream inputStream = null;
+    try
+    {	  
+	  inputStream = new BufferedInputStream(new FileInputStream(file));	
+	  inputStream.mark(MARK_LIMIT);	    
+	  AudioFileFormat aff = getAudioFileFormat(inputStream);
+	  inputStream.reset();
+      // Get Vorbis file info such as length in seconds.
+      VorbisFile vf = new VorbisFile(file.getAbsolutePath());      
+      return getAudioFileFormat(inputStream,(int) file.length(), (int) Math.round((vf.time_total(-1))*1000));
+    }
+	catch (JOrbisException e)
+	{
+		throw new IOException(e.getMessage());
+	}
+   finally
+   {
+     if (inputStream != null) inputStream.close();
+   }
+  }
+
+  /**
+   * Return the AudioFileFormat from the given URL.
+   */
+  public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException
+  {
+	if (TDebug.TraceAudioFileReader) TDebug.out("getAudioFileFormat(URL url)");
+    InputStream inputStream = url.openStream();
+    try
+    {
+      return getAudioFileFormat(inputStream);
+    }
+    finally
+    {
+		if (inputStream != null) inputStream.close();
+    }
+  }
+
+  /**
+   * Return the AudioFileFormat from the given InputStream.
+   */
+  public AudioFileFormat getAudioFileFormat(InputStream inputStream) throws UnsupportedAudioFileException, IOException
+  {
+	if (TDebug.TraceAudioFileReader) TDebug.out("getAudioFileFormat(InputStream inputStream)");
+	try
+	{
+		if (!inputStream.markSupported()) inputStream = new BufferedInputStream(inputStream);
+		inputStream.mark(MARK_LIMIT);
+		return getAudioFileFormat(inputStream, AudioSystem.NOT_SPECIFIED, AudioSystem.NOT_SPECIFIED);
+	}
+	finally
+	{
+		inputStream.reset();
+	}    
+  }
+
+  /**
+   * Return the AudioFileFormat from the given InputStream and length in bytes.
+   */
+  public AudioFileFormat getAudioFileFormat(InputStream inputStream, long medialength) throws UnsupportedAudioFileException, IOException
+  {
+	return getAudioFileFormat(inputStream, (int) medialength, AudioSystem.NOT_SPECIFIED);
+  }
+
+  
+  /**
+   * Return the AudioFileFormat from the given InputStream, length in bytes and length in milliseconds.
+   */
+  protected AudioFileFormat getAudioFileFormat(InputStream bitStream, int mediaLength, int totalms) throws UnsupportedAudioFileException, IOException
+  {
+	HashMap aff_properties = new HashMap();
+	HashMap af_properties = new HashMap();
+    if (totalms == AudioSystem.NOT_SPECIFIED)
+    {
+      totalms = 0;
+    }
+    if (totalms <= 0)
+    {
+      totalms = 0;
+    }
+    else
+    {
+		aff_properties.put("duration",new Long(totalms*1000));    	
+    }
+    oggBitStream_ = bitStream;
+    init_jorbis();
+    index = 0;
+    try
+    {
+      readHeaders(aff_properties, af_properties);
+    }
+    catch (IOException ioe)
+    {
+      if (TDebug.TraceAudioFileReader)
+      {
+		TDebug.out(ioe.getMessage());
+      }
+      throw new UnsupportedAudioFileException(ioe.getMessage());
+    }
+
+    String dmp = vorbisInfo.toString();
+    if (TDebug.TraceAudioFileReader)
+    {
+		TDebug.out(dmp);
+    }
+    int ind = dmp.lastIndexOf("bitrate:");    
+    int minbitrate = -1;
+	int nominalbitrate = -1;
+	int maxbitrate = -1;
+    if (ind != -1)
+    {
+      dmp = dmp.substring(ind + 8, dmp.length());
+      StringTokenizer st = new StringTokenizer(dmp, ",");
+	  if (st.hasMoreTokens())
+	  {
+		minbitrate = Integer.parseInt(st.nextToken());
+	  }
+	  if (st.hasMoreTokens())
+	  {
+		nominalbitrate = Integer.parseInt(st.nextToken());
+	  }
+	  if (st.hasMoreTokens())
+	  {
+		maxbitrate = Integer.parseInt(st.nextToken());
+	  }
+    }
+	if (nominalbitrate > 0) af_properties.put("bitrate",new Integer(nominalbitrate));
+	af_properties.put("vbr",new Boolean(true));
+	
+	if (minbitrate > 0)  aff_properties.put("ogg.bitrate.min.bps",new Integer(minbitrate));
+	if (maxbitrate > 0)  aff_properties.put("ogg.bitrate.max.bps",new Integer(maxbitrate));
+	if (nominalbitrate > 0) aff_properties.put("ogg.bitrate.nominal.bps",new Integer(nominalbitrate));
+	if (vorbisInfo.channels > 0) aff_properties.put("ogg.channels",new Integer(vorbisInfo.channels));
+	if (vorbisInfo.rate > 0) aff_properties.put("ogg.frequency.hz",new Integer(vorbisInfo.rate));
+	if (mediaLength > 0) aff_properties.put("ogg.length.bytes",new Integer(mediaLength));
+	aff_properties.put("ogg.version",new Integer(vorbisInfo.version));
+	
+    //AudioFormat.Encoding encoding = VorbisEncoding.VORBISENC;
+    //AudioFormat format = new VorbisAudioFormat(encoding, vorbisInfo.rate, AudioSystem.NOT_SPECIFIED, vorbisInfo.channels, AudioSystem.NOT_SPECIFIED, AudioSystem.NOT_SPECIFIED, true,af_properties);
+
+	// Patch from MS to ensure more SPI compatibility ...
+    float frameRate = -1;
+    if (nominalbitrate > 0) frameRate = nominalbitrate / 8;
+    else if (minbitrate > 0) frameRate = minbitrate / 8;
+    
+    AudioFormat.Encoding encoding = VorbisEncoding.VORBISENC;
+    // New Patch from MS:
+    AudioFormat format = new VorbisAudioFormat(encoding, vorbisInfo.rate, AudioSystem.NOT_SPECIFIED, vorbisInfo.channels, 1, frameRate, false, af_properties);
+    // Patch end
+	
+    return new VorbisAudioFileFormat(VorbisFileFormatType.OGG, format, AudioSystem.NOT_SPECIFIED, mediaLength,aff_properties);
+  }
+
+  /**
+   * Return the AudioInputStream from the given InputStream.
+   */
+  public AudioInputStream getAudioInputStream(InputStream inputStream) throws UnsupportedAudioFileException, IOException
+  {
+   if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(InputStream inputStream)");
+   return getAudioInputStream(inputStream, AudioSystem.NOT_SPECIFIED, AudioSystem.NOT_SPECIFIED);
+  }
+
+  /**
+   * Return the AudioInputStream from the given InputStream.
+   */
+  public AudioInputStream getAudioInputStream(InputStream inputStream, int medialength, int totalms) throws UnsupportedAudioFileException, IOException
+  {
+	if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(InputStream inputStreamint medialength, int totalms)");
+	try
+	{		
+		if (!inputStream.markSupported()) inputStream = new BufferedInputStream(inputStream);
+		inputStream.mark(MARK_LIMIT);
+		AudioFileFormat audioFileFormat = getAudioFileFormat(inputStream, medialength, totalms);
+		inputStream.reset();
+		return new AudioInputStream(inputStream, audioFileFormat.getFormat(), audioFileFormat.getFrameLength());
+	}
+	catch (UnsupportedAudioFileException e)
+	{
+		inputStream.reset();
+		throw e;
+	}
+	catch (IOException e)
+	{
+		inputStream.reset();
+		throw e;
+	}
+  }
+
+  /**
+   * Return the AudioInputStream from the given File.
+   */
+  public AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException
+  {
+	if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(File file)");
+    InputStream inputStream = new FileInputStream(file);
+    try
+    {
+      return getAudioInputStream(inputStream);
+    }
+    catch (UnsupportedAudioFileException e)
+    {
+	  if (inputStream != null) inputStream.close();
+      throw e;
+    }
+    catch (IOException e)
+    {
+	  if (inputStream != null) inputStream.close();
+      throw e;
+    }
+  }
+
+  /**
+   * Return the AudioInputStream from the given URL.
+   */
+  public AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException
+  {
+	if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(URL url)");
+    InputStream inputStream = url.openStream();
+    try
+    {
+      return getAudioInputStream(inputStream);
+    }
+    catch (UnsupportedAudioFileException e)
+    {
+	  if (inputStream != null) inputStream.close();
+      throw e;
+    }
+    catch (IOException e)
+    {
+	  if (inputStream != null) inputStream.close();
+      throw e;
+    }
+  }
+
+  /**
+   * Reads headers and comments.
+   */
+  private void readHeaders(HashMap aff_properties, HashMap af_properties) throws IOException
+  {
+	if(TDebug.TraceAudioConverter) TDebug.out("readHeaders(");
+	index = oggSyncState_.buffer(bufferSize_);
+	buffer = oggSyncState_.data;
+	bytes = readFromStream(buffer, index, bufferSize_);
+	if(bytes == -1)
+	{
+	  if(TDebug.TraceAudioConverter) TDebug.out("Cannot get any data from selected Ogg bitstream.");
+	  throw new IOException("Cannot get any data from selected Ogg bitstream.");
+	}
+	oggSyncState_.wrote(bytes);
+	if(oggSyncState_.pageout(oggPage_) != 1)
+	{
+	  if(bytes < bufferSize_)
+	  {
+		throw new IOException("EOF");
+	  }
+	  if(TDebug.TraceAudioConverter) TDebug.out("Input does not appear to be an Ogg bitstream.");
+	  throw new IOException("Input does not appear to be an Ogg bitstream.");
+	}	
+	oggStreamState_.init(oggPage_.serialno());
+	vorbisInfo.init();
+	vorbisComment.init();
+	aff_properties.put("ogg.serial",new Integer(oggPage_.serialno()));
+	if(oggStreamState_.pagein(oggPage_) < 0)
+	{
+	  // error; stream version mismatch perhaps
+	  if(TDebug.TraceAudioConverter) TDebug.out("Error reading first page of Ogg bitstream data.");
+	  throw new IOException("Error reading first page of Ogg bitstream data.");
+	}
+	if(oggStreamState_.packetout(oggPacket_) != 1)
+	{
+	  // no page? must not be vorbis
+	  if(TDebug.TraceAudioConverter) TDebug.out("Error reading initial header packet.");
+	  throw new IOException("Error reading initial header packet.");
+	}
+	if(vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_) < 0)
+	{
+	  // error case; not a vorbis header
+	  if(TDebug.TraceAudioConverter) TDebug.out("This Ogg bitstream does not contain Vorbis audio data.");
+	  throw new IOException("This Ogg bitstream does not contain Vorbis audio data.");
+	}
+	int i = 0;
+	while(i < 2)
+	{
+	  while(i < 2)
+	  {
+		int result = oggSyncState_.pageout(oggPage_);
+		if(result == 0)
+		{
+		  break;
+		} // Need more data
+		if(result == 1)
+		{
+		  oggStreamState_.pagein(oggPage_);
+		  while(i < 2)
+		  {
+			result = oggStreamState_.packetout(oggPacket_);
+			if(result == 0)
+			{
+			  break;
+			}
+			if(result == -1)
+			{
+			  if(TDebug.TraceAudioConverter) TDebug.out("Corrupt secondary header.  Exiting.");
+			  throw new IOException("Corrupt secondary header.  Exiting.");
+			}
+			vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_);
+			i++;
+		  }
+		}
+	  }
+	  index = oggSyncState_.buffer(bufferSize_);
+	  buffer = oggSyncState_.data;
+	  bytes = readFromStream(buffer, index, bufferSize_);
+	  if(bytes == -1)
+	  {
+		break;
+	  }
+	  if(bytes == 0 && i < 2)
+	  {
+		if(TDebug.TraceAudioConverter) TDebug.out("End of file before finding all Vorbis headers!");
+		throw new IOException("End of file before finding all Vorbis  headers!");
+	  }
+	  oggSyncState_.wrote(bytes);
+	}
+	// Read Ogg Vorbis comments.
+	byte[][] ptr = vorbisComment.user_comments;
+	String currComment = "";
+	int c = 0;
+	for(int j = 0; j < ptr.length; j++)
+	{
+	  if(ptr[j] == null)
+	  {
+		break;
+	  }
+	  currComment = (new String(ptr[j], 0, ptr[j].length - 1,"UTF-8")).trim();
+	  if(TDebug.TraceAudioConverter) TDebug.out(currComment);
+	  if (currComment.toLowerCase().startsWith("artist"))
+	  {
+		aff_properties.put("author",currComment.substring(7));	  	
+	  }
+	  else if (currComment.toLowerCase().startsWith("title"))
+	  {
+		aff_properties.put("title",currComment.substring(6));	  	
+	  }
+	  else if (currComment.toLowerCase().startsWith("album"))
+	  {
+		aff_properties.put("album",currComment.substring(6));	  	
+	  }
+	  else if (currComment.toLowerCase().startsWith("date"))
+	  {
+		aff_properties.put("date",currComment.substring(5));
+	  }
+	  else if (currComment.toLowerCase().startsWith("copyright"))
+	  {
+		aff_properties.put("copyright",currComment.substring(10));	  	
+	  }
+	  else if (currComment.toLowerCase().startsWith("comment"))
+	  {
+		aff_properties.put("comment",currComment.substring(8));
+	  }
+	  else if (currComment.toLowerCase().startsWith("genre"))
+	  {
+		aff_properties.put("ogg.comment.genre",currComment.substring(6));	
+	  }
+	  else if (currComment.toLowerCase().startsWith("tracknumber"))
+	  {
+		aff_properties.put("ogg.comment.track",currComment.substring(12));	
+	  }
+	  else
+	  {
+		c++;
+		aff_properties.put("ogg.comment.ext."+c,currComment);
+	  }
+	  aff_properties.put("ogg.comment.encodedby",new String(vorbisComment.vendor, 0, vorbisComment.vendor.length - 1));
+	}
+  }
+
+  /**
+   * Reads from the oggBitStream_ a specified number of Bytes(bufferSize_) worth
+   * starting at index and puts them in the specified buffer[].
+   *
+   * @return the number of bytes read or -1 if error.
+   */
+  private int readFromStream(byte[] buffer, int index, int bufferSize_)
+  {
+    int bytes = 0;
+    try
+    {
+      bytes = oggBitStream_.read(buffer, index, bufferSize_);
+    }
+    catch (Exception e)
+    {
+      if (TDebug.TraceAudioFileReader)
+      {
+        TDebug.out("Cannot Read Selected Song");
+      }
+      bytes = -1;
+    }
+    return bytes;
+  }
+
+  /**
+   * Initializes all the jOrbis and jOgg vars that are used for song playback.
+   */
+  private void init_jorbis()
+  {
+    oggSyncState_ = new SyncState();
+    oggStreamState_ = new StreamState();
+    oggPage_ = new Page();
+    oggPacket_ = new Packet();
+    vorbisInfo = new Info();
+    vorbisComment = new Comment();
+    vorbisDspState = new DspState();
+    vorbisBlock = new Block(vorbisDspState);
+    buffer = null;
+    bytes = 0;
+    oggSyncState_.init();
+  }
+}

+ 66 - 0
ToolKit/libs/OggUtils/src/javazoom/spi/vorbis/sampled/file/VorbisAudioFormat.java

@@ -0,0 +1,66 @@
+/*
+ *   VorbisAudioFormat.
+ * 
+ *   JavaZOOM : vorbisspi@javazoom.net
+ *              http://www.javazoom.net 
+ *
+ *   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.
+ *
+ */
+ 
+package javazoom.spi.vorbis.sampled.file;
+
+import java.util.Map;
+
+import javax.sound.sampled.AudioFormat;
+
+import org.tritonus.share.sampled.TAudioFormat;
+
+/**
+ * @author JavaZOOM
+ */
+public class VorbisAudioFormat extends TAudioFormat
+{	
+	/**
+	 * Constructor.
+	 * @param encoding
+	 * @param nFrequency
+	 * @param SampleSizeInBits
+	 * @param nChannels
+	 * @param FrameSize
+	 * @param FrameRate
+	 * @param isBigEndian
+	 * @param properties
+	 */
+	public VorbisAudioFormat(AudioFormat.Encoding encoding, float nFrequency, int SampleSizeInBits, int nChannels, int FrameSize, float FrameRate, boolean isBigEndian, Map properties)
+	{
+		super(encoding, nFrequency, SampleSizeInBits, nChannels, FrameSize, FrameRate, isBigEndian, properties);
+	}
+
+	/**
+	 * Ogg Vorbis audio format parameters. 
+	 * Some parameters might be unavailable. So availability test is required before reading any parameter.  
+	 *
+	 * <br>AudioFormat parameters.
+	 * <ul>
+	 * <li><b>bitrate</b> [Integer], bitrate in bits per seconds, average bitrate for VBR enabled stream.
+	 * <li><b>vbr</b> [Boolean], VBR flag.
+	 * </ul>
+	 */
+	public Map properties()
+	{
+		return super.properties();	
+	}
+}	

+ 41 - 0
ToolKit/libs/OggUtils/src/javazoom/spi/vorbis/sampled/file/VorbisEncoding.java

@@ -0,0 +1,41 @@
+/*
+ *   VorbisEncoding.
+ * 
+ *   JavaZOOM : vorbisspi@javazoom.net
+ *              http://www.javazoom.net
+ * 
+ *   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.
+ *
+ */
+
+package javazoom.spi.vorbis.sampled.file;
+
+import javax.sound.sampled.AudioFormat;
+
+/**
+ * Encodings used by the VORBIS audio decoder.
+ */
+public class VorbisEncoding extends AudioFormat.Encoding
+{
+  public static final AudioFormat.Encoding VORBISENC = new VorbisEncoding("VORBISENC");
+
+  /**
+   * Constructors.
+   */
+  public VorbisEncoding(String name)
+  {
+    super(name);
+  }
+}

+ 41 - 0
ToolKit/libs/OggUtils/src/javazoom/spi/vorbis/sampled/file/VorbisFileFormatType.java

@@ -0,0 +1,41 @@
+/*
+ *   VorbisFileFormatType.
+ * 
+ *   JavaZOOM : vorbisspi@javazoom.net
+ *              http://www.javazoom.net
+ * 
+ *   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.
+ *
+ */
+
+package javazoom.spi.vorbis.sampled.file;
+
+import javax.sound.sampled.AudioFileFormat;
+
+/**
+ * FileFormatTypes used by the VORBIS audio decoder.
+ */
+public class VorbisFileFormatType extends AudioFileFormat.Type
+{
+  public static final AudioFileFormat.Type VORBIS = new VorbisFileFormatType("VORBIS", "ogg");
+  public static final AudioFileFormat.Type OGG = new VorbisFileFormatType("OGG", "ogg");
+  /**
+   * Constructor.
+   */
+  public VorbisFileFormatType(String name, String extension)
+  {
+    super(name, extension);
+  }
+}

BIN
ToolKit/libs/OggUtils/vorbisspi1.0.3.jar


BIN
ToolKit/libs/aspectJ/aspectj-1.7.3-src.jar


BIN
ToolKit/libs/aspectJ/aspectj-1.7.3.jar


BIN
ToolKit/libs/aspectJ/aspectjrt.jar


BIN
ToolKit/libs/aspectJ/aspectjrt1.7.3-src.jar


BIN
ToolKit/libs/aspectJ/aspectjtools.jar


BIN
ToolKit/libs/aspectJ/aspectjtools1.7.3-src.jar


BIN
ToolKit/libs/aspectJ/aspectjweaver.jar


BIN
ToolKit/libs/aspectJ/aspectjweaver1.7.3-src.jar


BIN
ToolKit/libs/aspectJ/org.aspectj.matcher-1.7.3-src.jar


BIN
ToolKit/libs/aspectJ/org.aspectj.matcher.jar


BIN
ToolKit/libs/m4a-TK/jaad-0.8.4-src.zip


BIN
ToolKit/libs/m4a-TK/jaad-0.8.4.jar


BIN
ToolKit/libs/mp4rawparse/isoparser-1.0-RC-1-javadoc.jar


BIN
ToolKit/libs/mp4rawparse/isoparser-1.0-RC-1-sources.jar


BIN
ToolKit/libs/mp4rawparse/isoparser-1.0-RC-1.jar


+ 37 - 0
ToolKit/libs/nblibraries.properties

@@ -1,3 +1,14 @@
+libs.aspectJ.classpath=\
+    ${base}/aspectJ/aspectjrt.jar;\
+    ${base}/aspectJ/aspectjtools.jar;\
+    ${base}/aspectJ/aspectjweaver.jar;\
+    ${base}/aspectJ/org.aspectj.matcher.jar
+libs.aspectJ.displayName=aspectJ
+libs.aspectJ.src=\
+    ${base}/aspectJ/aspectjrt1.7.3-src.jar!//;\
+    ${base}/aspectJ/aspectjtools1.7.3-src.jar!//;\
+    ${base}/aspectJ/aspectjweaver1.7.3-src.jar!//;\
+    ${base}/aspectJ/org.aspectj.matcher-1.7.3-src.jar!//
 libs.COmmons-Exec.classpath=\
     ${base}/COmmons-Exec/commons-exec-1.1.jar
 libs.commons-IO.classpath=\
@@ -33,10 +44,36 @@ libs.JNA.src=\
     ${base}/JNA/src/
 libs.jRegistry.classpath=\
     ${base}/jRegistry/registry.jar
+libs.m4a-TK.classpath=\
+    ${base}/m4a-TK/jaad-0.8.4.jar
+libs.m4a-TK.displayName=m4a-TK
+libs.m4a-TK.src=\
+    ${base}/m4a-TK/jaad-0.8.4-src.zip!//
+libs.Mp3Utils.classpath=\
+    ${base}/Mp3Utils/jl1.0.1.jar;\
+    ${base}/Mp3Utils/tritonus_share.jar;\
+    ${base}/Mp3Utils/mp3spi1.9.5.jar
+libs.Mp3Utils.displayName=Mp3Utils
+libs.Mp3Utils.src=\
+    ${base}/Mp3Utils/src/
+libs.mp4rawparse.classpath=\
+    ${base}/mp4rawparse/isoparser-1.0-RC-1.jar
+libs.mp4rawparse.displayName=mp4rawparse
+libs.mp4rawparse.javadoc=\
+    ${base}/mp4rawparse/isoparser-1.0-RC-1-javadoc.jar!//
+libs.mp4rawparse.src=\
+    ${base}/mp4rawparse/isoparser-1.0-RC-1-sources.jar!//
 libs.MySQLDriver.classpath=\
     ${base}/MySQLDriver/mysql-connector-java-5.1.18-bin.jar
 libs.MySQLDriver.displayName=MySQL JDBC Driver
 libs.MySQLDriver.prop-maven-dependencies=mysql:mysql-connector-java:5.1.18:jar
+libs.OggUtils.classpath=\
+    ${base}/OggUtils/vorbisspi1.0.3.jar;\
+    ${base}/OggUtils/jogg-0.0.7.jar;\
+    ${base}/OggUtils/jorbis-0.0.15.jar
+libs.OggUtils.displayName=OggUtils
+libs.OggUtils.src=\
+    ${base}/OggUtils/src/
 libs.SnakeYaml.classpath=\
     ${base}/SnakeYaml/snakeyaml-1.10.jar
 libs.SQlite-JDBC.classpath=\

+ 28 - 16
ToolKit/src/de/nplusc/izc/tools/baseTools/Tools.java

@@ -549,7 +549,9 @@ public class Tools
     {
         return runSingleCmd(logg, legacy, sret, asArray, tx, null, runnable);
     }
-    public static String runSingleCmd(boolean logg, boolean legacy, boolean sret,boolean asArray,JTextArea tx, PrintStream pw, String... runnable)
+    
+    private static Process p;
+    public static String runSingleCmd(boolean logg, boolean legacy, boolean sret,boolean asArray,final JTextArea tx, final PrintStream pw, String... runnable)
     {
         execCrashed = false;
                 String cret = "";
@@ -589,33 +591,43 @@ public class Tools
             }
             else
             {
-                Process p = null;
+                p = null;
                 if(!asArray)
                     p=Runtime.getRuntime().exec(cmd);
                 else
                     p=Runtime.getRuntime().exec(runnable);
                 if(tx!=null)
                 {
-                    Scanner scanner = new Scanner(p.getInputStream());
-                    Scanner scannerE = new Scanner(p.getErrorStream());
-                    while ((scanner.hasNextLine()||scanner.hasNextLine()))
+                    new Thread(
+                    new Runnable()
                     {
-                        if(scanner.hasNextLine())
+
+                        @Override
+                        public void run()
                         {
-                            String l = scanner.nextLine();
-                            tx.append(l+"\n");
-                            if(pw!=null)
-                                pw.println(l);
-                        }
-                        if(scannerE.hasNextLine())
+                        Scanner scanner = new Scanner(p.getInputStream());
+                        Scanner scannerE = new Scanner(p.getErrorStream());
+                        while ((scanner.hasNextLine()||scanner.hasNextLine()))
                         {
-                            String l = scannerE.nextLine();
-                            tx.append(l+"\n");
-                            if(pw!=null)
-                                pw.println(l);
+                            if(scanner.hasNextLine())
+                            {
+                                String l = scanner.nextLine();
+                                tx.append(l+"\n");
+                                if(pw!=null)
+                                    pw.println(l);
+                            }
+                            if(scannerE.hasNextLine())
+                            {
+                                String l = scannerE.nextLine();
+                                tx.append(l+"\n");
+                                if(pw!=null)
+                                    pw.println(l);
+                            }
                         }
                     }
                 }
+            ).start();
+                }
                 if (sret)
                 {
                     cret = new BufferedReader(new InputStreamReader(p.getInputStream())).readLine();