summaryrefslogtreecommitdiff
path: root/songdbj/javazoom/spi
diff options
context:
space:
mode:
authorBjörn Stenberg <bjorn@haxx.se>2007-01-08 23:53:00 +0000
committerBjörn Stenberg <bjorn@haxx.se>2007-01-08 23:53:00 +0000
commit7039a05147b8bbfc829babea1c65bd436450b505 (patch)
tree4ba555eb84ed97b72b0575034d5b0530a393713e /songdbj/javazoom/spi
parent6d4c19707ef95942e323cbdc89fbbfdbe45e7cc5 (diff)
downloadrockbox-7039a05147b8bbfc829babea1c65bd436450b505.tar.gz
rockbox-7039a05147b8bbfc829babea1c65bd436450b505.zip
Splitting out songdbj
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11953 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'songdbj/javazoom/spi')
-rw-r--r--songdbj/javazoom/spi/PropertiesContainer.java31
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/convert/DecodedMpegAudioInputStream.java334
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/convert/MpegFormatConversionProvider.java120
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/IcyListener.java131
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileFormat.java103
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileReader.java772
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFormat.java67
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/MpegEncoding.java47
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/MpegFileFormatType.java40
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyInputStream.java412
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyTag.java42
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3MetadataParser.java50
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3Tag.java52
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3TagParseSupport.java62
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/StringableTag.java36
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseEvent.java44
-rw-r--r--songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseListener.java37
-rw-r--r--songdbj/javazoom/spi/vorbis/sampled/convert/DecodedVorbisAudioInputStream.java519
-rw-r--r--songdbj/javazoom/spi/vorbis/sampled/convert/VorbisFormatConversionProvider.java244
-rw-r--r--songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileFormat.java85
-rw-r--r--songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileReader.java502
-rw-r--r--songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFormat.java66
-rw-r--r--songdbj/javazoom/spi/vorbis/sampled/file/VorbisEncoding.java41
-rw-r--r--songdbj/javazoom/spi/vorbis/sampled/file/VorbisFileFormatType.java41
24 files changed, 0 insertions, 3878 deletions
diff --git a/songdbj/javazoom/spi/PropertiesContainer.java b/songdbj/javazoom/spi/PropertiesContainer.java
deleted file mode 100644
index 27ed85f904..0000000000
--- a/songdbj/javazoom/spi/PropertiesContainer.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * PropertiesContainer.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23
24package javazoom.spi;
25
26import java.util.Map;
27
28public interface PropertiesContainer
29{
30 public Map properties();
31}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/convert/DecodedMpegAudioInputStream.java b/songdbj/javazoom/spi/mpeg/sampled/convert/DecodedMpegAudioInputStream.java
deleted file mode 100644
index e4e6fed00a..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/convert/DecodedMpegAudioInputStream.java
+++ /dev/null
@@ -1,334 +0,0 @@
1/*
2 * DecodedMpegAudioInputStream.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *------------------------------------------------------------------------
22 */
23
24package javazoom.spi.mpeg.sampled.convert;
25import java.io.IOException;
26import java.io.InputStream;
27import java.util.HashMap;
28import java.util.Map;
29
30import javax.sound.sampled.AudioFormat;
31import javax.sound.sampled.AudioInputStream;
32
33import javazoom.jl.decoder.Bitstream;
34import javazoom.jl.decoder.BitstreamException;
35import javazoom.jl.decoder.Decoder;
36import javazoom.jl.decoder.DecoderException;
37import javazoom.jl.decoder.Equalizer;
38import javazoom.jl.decoder.Header;
39import javazoom.jl.decoder.Obuffer;
40import javazoom.spi.PropertiesContainer;
41import javazoom.spi.mpeg.sampled.file.IcyListener;
42import javazoom.spi.mpeg.sampled.file.tag.TagParseEvent;
43import javazoom.spi.mpeg.sampled.file.tag.TagParseListener;
44
45import org.tritonus.share.TDebug;
46import org.tritonus.share.sampled.convert.TAsynchronousFilteredAudioInputStream;
47
48/**
49 * Main decoder.
50 */
51public class DecodedMpegAudioInputStream extends TAsynchronousFilteredAudioInputStream implements PropertiesContainer, TagParseListener
52{
53 private InputStream m_encodedStream;
54 private Bitstream m_bitstream;
55 private Decoder m_decoder;
56 private Equalizer m_equalizer;
57 private float[] m_equalizer_values;
58 private Header m_header;
59 private DMAISObuffer m_oBuffer;
60
61 // Bytes info.
62 private long byteslength = -1;
63 private long currentByte = 0;
64 // Frame info.
65 private int frameslength = -1;
66 private long currentFrame = 0;
67 private int currentFramesize = 0;
68 private int currentBitrate = -1;
69 // Time info.
70 private long currentMicrosecond = 0;
71 // Shoutcast stream info
72 private IcyListener shoutlst = null;
73
74
75 private HashMap properties = null;
76
77 public DecodedMpegAudioInputStream(AudioFormat outputFormat, AudioInputStream inputStream)
78 {
79 super(outputFormat, -1);
80 if (TDebug.TraceAudioConverter)
81 {
82 TDebug.out(">DecodedMpegAudioInputStream(AudioFormat outputFormat, AudioInputStream inputStream)");
83 }
84 try
85 {
86 // Try to find out inputstream length to allow skip.
87 byteslength = inputStream.available();
88 }
89 catch (IOException e)
90 {
91 TDebug.out("DecodedMpegAudioInputStream : Cannot run inputStream.available() : "+e.getMessage());
92 byteslength = -1;
93 }
94 m_encodedStream = inputStream;
95 shoutlst = IcyListener.getInstance();
96 shoutlst.reset();
97 m_bitstream = new Bitstream(inputStream);
98 m_decoder = new Decoder(null);
99 m_equalizer = new Equalizer();
100 m_equalizer_values = new float[32];
101 for (int b=0;b<m_equalizer.getBandCount();b++)
102 {
103 m_equalizer_values[b] = m_equalizer.getBand(b);
104 }
105 m_decoder.setEqualizer(m_equalizer);
106 m_oBuffer = new DMAISObuffer(outputFormat.getChannels());
107 m_decoder.setOutputBuffer(m_oBuffer);
108 try
109 {
110 m_header = m_bitstream.readFrame();
111 if ((m_header != null) && (frameslength == -1) && (byteslength > 0)) frameslength = m_header.max_number_of_frames((int)byteslength);
112 }
113 catch (BitstreamException e)
114 {
115 TDebug.out("DecodedMpegAudioInputStream : Cannot read first frame : "+e.getMessage());
116 byteslength = -1;
117 }
118 properties = new HashMap();
119 }
120
121 /**
122 * Return dynamic properties.
123 *
124 * <ul>
125 * <li><b>mp3.frame</b> [Long], current frame position.
126 * <li><b>mp3.frame.bitrate</b> [Integer], bitrate of the current frame.
127 * <li><b>mp3.frame.size.bytes</b> [Integer], size in bytes of the current frame.
128 * <li><b>mp3.position.byte</b> [Long], current position in bytes in the stream.
129 * <li><b>mp3.position.microseconds</b> [Long], elapsed microseconds.
130 * <li><b>mp3.equalizer</b> float[32], interactive equalizer array, values could be in [-1.0, +1.0].
131 * <li><b>mp3.shoutcast.metadata.key</b> [String], Shoutcast meta key with matching value.
132 * <br>For instance :
133 * <br>mp3.shoutcast.metadata.StreamTitle=Current song playing in stream.
134 * <br>mp3.shoutcast.metadata.StreamUrl=Url info.
135 * </ul>
136 */
137 public Map properties()
138 {
139 properties.put("mp3.frame",new Long(currentFrame));
140 properties.put("mp3.frame.bitrate",new Integer(currentBitrate));
141 properties.put("mp3.frame.size.bytes",new Integer(currentFramesize));
142 properties.put("mp3.position.byte",new Long(currentByte));
143 properties.put("mp3.position.microseconds",new Long(currentMicrosecond));
144 properties.put("mp3.equalizer",m_equalizer_values);
145 // Optionnal shoutcast stream meta-data.
146 if (shoutlst != null)
147 {
148 String surl = shoutlst.getStreamUrl();
149 String stitle = shoutlst.getStreamTitle();
150 if ((stitle != null) && (stitle.trim().length()>0)) properties.put("mp3.shoutcast.metadata.StreamTitle",stitle);
151 if ((surl != null) && (surl.trim().length()>0)) properties.put("mp3.shoutcast.metadata.StreamUrl",surl);
152 }
153 return properties;
154 }
155
156 public void execute()
157 {
158 if (TDebug.TraceAudioConverter) TDebug.out("execute() : begin");
159 try
160 {
161 // Following line hangs when FrameSize is available in AudioFormat.
162 Header header = null;
163 if (m_header == null) header = m_bitstream.readFrame();
164 else header = m_header;
165 if (TDebug.TraceAudioConverter) TDebug.out("execute() : header = "+header);
166 if (header == null)
167 {
168 if (TDebug.TraceAudioConverter)
169 {
170 TDebug.out("header is null (end of mpeg stream)");
171 }
172 getCircularBuffer().close();
173 return;
174 }
175 currentFrame++;
176 currentBitrate = header.bitrate_instant();
177 currentFramesize = header.calculate_framesize();
178 currentByte = currentByte + currentFramesize;
179 currentMicrosecond = (long) (currentFrame* header.ms_per_frame()*1000.0f);
180 for (int b=0;b<m_equalizer_values.length;b++)
181 {
182 m_equalizer.setBand(b,m_equalizer_values[b]);
183 }
184 m_decoder.setEqualizer(m_equalizer);
185 Obuffer decoderOutput = m_decoder.decodeFrame(header, m_bitstream);
186 m_bitstream.closeFrame();
187 getCircularBuffer().write(m_oBuffer.getBuffer(), 0, m_oBuffer.getCurrentBufferSize());
188 m_oBuffer.reset();
189 if (m_header != null) m_header = null;
190 }
191 catch (BitstreamException e)
192 {
193 if (TDebug.TraceAudioConverter)
194 {
195 TDebug.out(e);
196 }
197 }
198 catch (DecoderException e)
199 {
200 if (TDebug.TraceAudioConverter)
201 {
202 TDebug.out(e);
203 }
204 }
205 if (TDebug.TraceAudioConverter) TDebug.out("execute() : end");
206 }
207
208 public long skip(long bytes)
209 {
210 if ((byteslength > 0) && (frameslength > 0))
211 {
212 float ratio = bytes*1.0f/byteslength*1.0f;
213 long bytesread = skipFrames((long) (ratio*frameslength));
214 currentByte = currentByte + bytesread;
215 return bytesread;
216 }
217 else return -1;
218 }
219
220 /**
221 * Skip frames.
222 * You don't need to call it severals times, it will exactly skip given frames number.
223 * @param frames
224 * @return bytes length skipped matching to frames skipped.
225 */
226 public long skipFrames(long frames)
227 {
228 if (TDebug.TraceAudioConverter) TDebug.out("skip(long frames) : begin");
229 int framesRead = 0;
230 int bytesReads = 0;
231 try
232 {
233 for (int i=0;i<frames;i++)
234 {
235 Header header = m_bitstream.readFrame();
236 if (header != null)
237 {
238 int fsize = header.calculate_framesize();
239 bytesReads = bytesReads + fsize;
240 }
241 m_bitstream.closeFrame();
242 framesRead++;
243 }
244 }
245 catch (BitstreamException e)
246 {
247 if (TDebug.TraceAudioConverter) TDebug.out(e);
248 }
249 if (TDebug.TraceAudioConverter) TDebug.out("skip(long frames) : end");
250 currentFrame = currentFrame + framesRead;
251 return bytesReads;
252 }
253
254 private boolean isBigEndian()
255 {
256 return getFormat().isBigEndian();
257 }
258
259 public void close() throws IOException
260 {
261 super.close();
262 m_encodedStream.close();
263 }
264
265 private class DMAISObuffer extends Obuffer
266 {
267 private int m_nChannels;
268 private byte[] m_abBuffer;
269 private int[] m_anBufferPointers;
270 private boolean m_bIsBigEndian;
271 public DMAISObuffer(int nChannels)
272 {
273 m_nChannels = nChannels;
274 m_abBuffer = new byte[OBUFFERSIZE * nChannels];
275 m_anBufferPointers = new int[nChannels];
276 reset();
277 m_bIsBigEndian = DecodedMpegAudioInputStream.this.isBigEndian();
278 }
279 public void append(int nChannel, short sValue)
280 {
281 byte bFirstByte;
282 byte bSecondByte;
283 if (m_bIsBigEndian)
284 {
285 bFirstByte = (byte) ((sValue >>> 8) & 0xFF);
286 bSecondByte = (byte) (sValue & 0xFF);
287 }
288 else // little endian
289 {
290 bFirstByte = (byte) (sValue & 0xFF);
291 bSecondByte = (byte) ((sValue >>> 8) & 0xFF);
292 }
293 m_abBuffer[m_anBufferPointers[nChannel]] = bFirstByte;
294 m_abBuffer[m_anBufferPointers[nChannel] + 1] = bSecondByte;
295 m_anBufferPointers[nChannel] += m_nChannels * 2;
296 }
297 public void set_stop_flag()
298 {
299 }
300 public void close()
301 {
302 }
303 public void write_buffer(int nValue)
304 {
305 }
306 public void clear_buffer()
307 {
308 }
309 public byte[] getBuffer()
310 {
311 return m_abBuffer;
312 }
313 public int getCurrentBufferSize()
314 {
315 return m_anBufferPointers[0];
316 }
317 public void reset()
318 {
319 for (int i = 0; i < m_nChannels; i++)
320 {
321 /* Points to byte location,
322 * implicitely assuming 16 bit
323 * samples.
324 */
325 m_anBufferPointers[i] = i * 2;
326 }
327 }
328 }
329
330 public void tagParsed(TagParseEvent tpe)
331 {
332 System.out.println("TAG:"+tpe.getTag());
333 }
334}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/convert/MpegFormatConversionProvider.java b/songdbj/javazoom/spi/mpeg/sampled/convert/MpegFormatConversionProvider.java
deleted file mode 100644
index 1a3d51d9ad..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/convert/MpegFormatConversionProvider.java
+++ /dev/null
@@ -1,120 +0,0 @@
1/*
2 * MpegFormatConversionProvider.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * ---------------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * --------------------------------------------------------------------------
22 */
23
24
25package javazoom.spi.mpeg.sampled.convert;
26
27
28import java.util.Arrays;
29
30import javax.sound.sampled.AudioFormat;
31import javax.sound.sampled.AudioInputStream;
32import javax.sound.sampled.AudioSystem;
33
34import javazoom.spi.mpeg.sampled.file.MpegEncoding;
35
36import org.tritonus.share.TDebug;
37import org.tritonus.share.sampled.Encodings;
38import org.tritonus.share.sampled.convert.TEncodingFormatConversionProvider;
39
40/**
41 * ConversionProvider for MPEG files.
42 */
43public class MpegFormatConversionProvider extends TEncodingFormatConversionProvider
44{
45 private static final AudioFormat.Encoding MP3 = Encodings.getEncoding("MP3");
46 private static final AudioFormat.Encoding PCM_SIGNED = Encodings.getEncoding("PCM_SIGNED");
47
48 private static final AudioFormat[] INPUT_FORMATS =
49 {
50 // mono
51 new AudioFormat(MP3, -1.0F, -1, 1, -1, -1.0F, false),
52 new AudioFormat(MP3, -1.0F, -1, 1, -1, -1.0F, true),
53 // stereo
54 new AudioFormat(MP3, -1.0F, -1, 2, -1, -1.0F, false),
55 new AudioFormat(MP3, -1.0F, -1, 2, -1, -1.0F, true),
56 };
57
58
59 private static final AudioFormat[] OUTPUT_FORMATS =
60 {
61 // mono, 16 bit signed
62 new AudioFormat(PCM_SIGNED, -1.0F, 16, 1, 2, -1.0F, false),
63 new AudioFormat(PCM_SIGNED, -1.0F, 16, 1, 2, -1.0F, true),
64 // stereo, 16 bit signed
65 new AudioFormat(PCM_SIGNED, -1.0F, 16, 2, 4, -1.0F, false),
66 new AudioFormat(PCM_SIGNED, -1.0F, 16, 2, 4, -1.0F, true),
67 };
68
69 /**
70 * Constructor.
71 */
72 public MpegFormatConversionProvider()
73 {
74 super(Arrays.asList(INPUT_FORMATS), Arrays.asList(OUTPUT_FORMATS));
75 if (TDebug.TraceAudioConverter)
76 {
77 TDebug.out(">MpegFormatConversionProvider()");
78 }
79 }
80
81 public AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream audioInputStream)
82 {
83 if (TDebug.TraceAudioConverter)
84 {
85 TDebug.out(">MpegFormatConversionProvider.getAudioInputStream(AudioFormat targetFormat, AudioInputStream audioInputStream):");
86 }
87 return new DecodedMpegAudioInputStream(targetFormat, audioInputStream);
88 }
89
90 /**
91 * Add conversion support for any MpegEncoding source with FrameRate or FrameSize not empty.
92 * @param targetFormat
93 * @param sourceFormat
94 * @return
95 */
96 public boolean isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat)
97 {
98 if (TDebug.TraceAudioConverter)
99 {
100 TDebug.out(">MpegFormatConversionProvider.isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat):");
101 TDebug.out("checking if conversion possible");
102 TDebug.out("from: " + sourceFormat);
103 TDebug.out("to: " + targetFormat);
104 }
105
106 boolean conversion = super.isConversionSupported(targetFormat, sourceFormat);
107 if (conversion == false)
108 {
109 AudioFormat.Encoding enc = sourceFormat.getEncoding();
110 if (enc instanceof MpegEncoding)
111 {
112 if ((sourceFormat.getFrameRate() != AudioSystem.NOT_SPECIFIED) || (sourceFormat.getFrameSize() != AudioSystem.NOT_SPECIFIED))
113 {
114 conversion = true;
115 }
116 }
117 }
118 return conversion;
119 }
120}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/IcyListener.java b/songdbj/javazoom/spi/mpeg/sampled/file/IcyListener.java
deleted file mode 100644
index 8e49e6e2ef..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/file/IcyListener.java
+++ /dev/null
@@ -1,131 +0,0 @@
1/*
2 * IcyListener.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23
24package javazoom.spi.mpeg.sampled.file;
25
26import javazoom.spi.mpeg.sampled.file.tag.MP3Tag;
27import javazoom.spi.mpeg.sampled.file.tag.TagParseEvent;
28import javazoom.spi.mpeg.sampled.file.tag.TagParseListener;
29
30/**
31 * This class (singleton) allow to be notified on shoutcast meta data
32 * while playing the stream (such as song title).
33 */
34public class IcyListener implements TagParseListener
35{
36 private static IcyListener instance = null;
37 private MP3Tag lastTag = null;
38 private String streamTitle = null;
39 private String streamUrl = null;
40
41
42 private IcyListener()
43 {
44 super();
45 }
46
47 public static synchronized IcyListener getInstance()
48 {
49 if (instance == null)
50 {
51 instance = new IcyListener();
52 }
53 return instance;
54 }
55
56 /* (non-Javadoc)
57 * @see javazoom.spi.mpeg.sampled.file.tag.TagParseListener#tagParsed(javazoom.spi.mpeg.sampled.file.tag.TagParseEvent)
58 */
59 public void tagParsed(TagParseEvent tpe)
60 {
61 lastTag = tpe.getTag();
62 String name = lastTag.getName();
63 if ((name != null) && (name.equalsIgnoreCase("streamtitle")))
64 {
65 streamTitle = (String) lastTag.getValue();
66 }
67 else if ((name != null) && (name.equalsIgnoreCase("streamurl")))
68 {
69 streamUrl = (String) lastTag.getValue();
70 }
71 }
72
73 /**
74 * @return
75 */
76 public MP3Tag getLastTag()
77 {
78 return lastTag;
79 }
80
81 /**
82 * @param tag
83 */
84 public void setLastTag(MP3Tag tag)
85 {
86 lastTag = tag;
87 }
88
89 /**
90 * @return
91 */
92 public String getStreamTitle()
93 {
94 return streamTitle;
95 }
96
97 /**
98 * @return
99 */
100 public String getStreamUrl()
101 {
102 return streamUrl;
103 }
104
105 /**
106 * @param string
107 */
108 public void setStreamTitle(String string)
109 {
110 streamTitle = string;
111 }
112
113 /**
114 * @param string
115 */
116 public void setStreamUrl(String string)
117 {
118 streamUrl = string;
119 }
120
121 /**
122 * Reset all properties.
123 */
124 public void reset()
125 {
126 lastTag = null;
127 streamTitle = null;
128 streamUrl = null;
129 }
130
131}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileFormat.java b/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileFormat.java
deleted file mode 100644
index afdc4c5e9c..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileFormat.java
+++ /dev/null
@@ -1,103 +0,0 @@
1/*
2 * MpegAudioFileFormat.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23package javazoom.spi.mpeg.sampled.file;
24
25import java.util.Map;
26
27import javax.sound.sampled.AudioFormat;
28
29import org.tritonus.share.sampled.file.TAudioFileFormat;
30
31/**
32 * @author JavaZOOM
33 */
34public class MpegAudioFileFormat extends TAudioFileFormat
35{
36 /**
37 * Contructor.
38 * @param type
39 * @param audioFormat
40 * @param nLengthInFrames
41 * @param nLengthInBytes
42 */
43 public MpegAudioFileFormat(Type type, AudioFormat audioFormat, int nLengthInFrames, int nLengthInBytes, Map properties)
44 {
45 super(type, audioFormat, nLengthInFrames, nLengthInBytes, properties);
46 }
47
48 /**
49 * MP3 audio file format parameters.
50 * Some parameters might be unavailable. So availability test is required before reading any parameter.
51 *
52 * <br>AudioFileFormat parameters.
53 * <ul>
54 * <li><b>duration</b> [Long], duration in microseconds.
55 * <li><b>title</b> [String], Title of the stream.
56 * <li><b>author</b> [String], Name of the artist of the stream.
57 * <li><b>album</b> [String], Name of the album of the stream.
58 * <li><b>date</b> [String], The date (year) of the recording or release of the stream.
59 * <li><b>copyright</b> [String], Copyright message of the stream.
60 * <li><b>comment</b> [String], Comment of the stream.
61 * </ul>
62 * <br>MP3 parameters.
63 * <ul>
64 * <li><b>mp3.version.mpeg</b> [String], mpeg version : 1,2 or 2.5
65 * <li><b>mp3.version.layer</b> [String], layer version 1, 2 or 3
66 * <li><b>mp3.version.encoding</b> [String], mpeg encoding : MPEG1, MPEG2-LSF, MPEG2.5-LSF
67 * <li><b>mp3.channels</b> [Integer], number of channels 1 : mono, 2 : stereo.
68 * <li><b>mp3.frequency.hz</b> [Integer], sampling rate in hz.
69 * <li><b>mp3.bitrate.nominal.bps</b> [Integer], nominal bitrate in bps.
70 * <li><b>mp3.length.bytes</b> [Integer], length in bytes.
71 * <li><b>mp3.length.frames</b> [Integer], length in frames.
72 * <li><b>mp3.framesize.bytes</b> [Integer], framesize of the first frame. framesize is not constant for VBR streams.
73 * <li><b>mp3.framerate.fps</b> [Float], framerate in frames per seconds.
74 * <li><b>mp3.header.pos</b> [Integer], position of first audio header (or ID3v2 size).
75 * <li><b>mp3.vbr</b> [Boolean], vbr flag.
76 * <li><b>mp3.vbr.scale</b> [Integer], vbr scale.
77 * <li><b>mp3.crc</b> [Boolean], crc flag.
78 * <li><b>mp3.original</b> [Boolean], original flag.
79 * <li><b>mp3.copyright</b> [Boolean], copyright flag.
80 * <li><b>mp3.padding</b> [Boolean], padding flag.
81 * <li><b>mp3.mode</b> [Integer], mode 0:STEREO 1:JOINT_STEREO 2:DUAL_CHANNEL 3:SINGLE_CHANNEL
82 * <li><b>mp3.id3tag.genre</b> [String], ID3 tag (v1 or v2) genre.
83 * <li><b>mp3.id3tag.track</b> [String], ID3 tag (v1 or v2) track info.
84 * <li><b>mp3.id3tag.encoded</b> [String], ID3 tag v2 encoded by info.
85 * <li><b>mp3.id3tag.composer</b> [String], ID3 tag v2 composer info.
86 * <li><b>mp3.id3tag.grouping</b> [String], ID3 tag v2 grouping info.
87 * <li><b>mp3.id3tag.disc</b> [String], ID3 tag v2 track info.
88 * <li><b>mp3.id3tag.v2</b> [InputStream], ID3v2 frames.
89 * <li><b>mp3.id3tag.v2.version</b> [String], ID3v2 major version (2=v2.2.0, 3=v2.3.0, 4=v2.4.0).
90 * <li><b>mp3.shoutcast.metadata.key</b> [String], Shoutcast meta key with matching value.
91 * <br>For instance :
92 * <br>mp3.shoutcast.metadata.icy-irc=#shoutcast
93 * <br>mp3.shoutcast.metadata.icy-metaint=8192
94 * <br>mp3.shoutcast.metadata.icy-genre=Trance Techno Dance
95 * <br>mp3.shoutcast.metadata.icy-url=http://www.di.fm
96 * <br>and so on ...
97 * </ul>
98 */
99 public Map properties()
100 {
101 return super.properties();
102 }
103}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileReader.java b/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileReader.java
deleted file mode 100644
index 54440551a1..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFileReader.java
+++ /dev/null
@@ -1,772 +0,0 @@
1/*
2 * MpegAudioFileReader.
3 *
4 * 12/31/04 : mp3spi.weak system property added to skip controls.
5 *
6 * 11/29/04 : ID3v2.2, v2.3 & v2.4 support improved.
7 * "mp3.id3tag.composer" (TCOM/TCM) added
8 * "mp3.id3tag.grouping" (TIT1/TT1) added
9 * "mp3.id3tag.disc" (TPA/TPOS) added
10 * "mp3.id3tag.encoded" (TEN/TENC) added
11 * "mp3.id3tag.v2.version" added
12 *
13 * 11/28/04 : String encoding bug fix in chopSubstring method.
14 *
15 * JavaZOOM : mp3spi@javazoom.net
16 * http://www.javazoom.net
17 *
18 *-----------------------------------------------------------------------
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU Library General Public License as published
21 * by the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU Library General Public License for more details.
28 *
29 * You should have received a copy of the GNU Library General Public
30 * License along with this program; if not, write to the Free Software
31 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 *----------------------------------------------------------------------
33 */
34
35package javazoom.spi.mpeg.sampled.file;
36
37
38import java.io.BufferedInputStream;
39import java.io.File;
40import java.io.FileInputStream;
41import java.io.IOException;
42import java.io.InputStream;
43import java.io.PushbackInputStream;
44import java.io.UnsupportedEncodingException;
45import java.net.URL;
46import java.net.URLConnection;
47import java.security.AccessControlException;
48import java.util.HashMap;
49
50import javax.sound.sampled.AudioFileFormat;
51import javax.sound.sampled.AudioFormat;
52import javax.sound.sampled.AudioInputStream;
53import javax.sound.sampled.AudioSystem;
54import javax.sound.sampled.UnsupportedAudioFileException;
55
56import javazoom.jl.decoder.Bitstream;
57import javazoom.jl.decoder.Header;
58import javazoom.spi.mpeg.sampled.file.tag.IcyInputStream;
59import javazoom.spi.mpeg.sampled.file.tag.MP3Tag;
60
61import org.tritonus.share.TDebug;
62import org.tritonus.share.sampled.file.TAudioFileReader;
63
64/**
65 * This class implements AudioFileReader for MP3 SPI.
66 */
67public class MpegAudioFileReader extends TAudioFileReader
68{
69 private final int SYNC = 0xFFE00000;
70 private String weak = null;
71 private final AudioFormat.Encoding[][] sm_aEncodings =
72 {
73 {MpegEncoding.MPEG2L1, MpegEncoding.MPEG2L2, MpegEncoding.MPEG2L3},
74 {MpegEncoding.MPEG1L1, MpegEncoding.MPEG1L2, MpegEncoding.MPEG1L3},
75 {MpegEncoding.MPEG2DOT5L1, MpegEncoding.MPEG2DOT5L2, MpegEncoding.MPEG2DOT5L3},
76
77 };
78
79 private static final int INITAL_READ_LENGTH = 64000;
80 private static final int MARK_LIMIT = INITAL_READ_LENGTH + 1;
81
82 private static final String[] id3v1genres = {
83 "Blues"
84 , "Classic Rock"
85 , "Country"
86 , "Dance"
87 , "Disco"
88 , "Funk"
89 , "Grunge"
90 , "Hip-Hop"
91 , "Jazz"
92 , "Metal"
93 , "New Age"
94 , "Oldies"
95 , "Other"
96 , "Pop"
97 , "R&B"
98 , "Rap"
99 , "Reggae"
100 , "Rock"
101 , "Techno"
102 , "Industrial"
103 , "Alternative"
104 , "Ska"
105 , "Death Metal"
106 , "Pranks"
107 , "Soundtrack"
108 , "Euro-Techno"
109 , "Ambient"
110 , "Trip-Hop"
111 , "Vocal"
112 , "Jazz+Funk"
113 , "Fusion"
114 , "Trance"
115 , "Classical"
116 , "Instrumental"
117 , "Acid"
118 , "House"
119 , "Game"
120 , "Sound Clip"
121 , "Gospel"
122 , "Noise"
123 , "AlternRock"
124 , "Bass"
125 , "Soul"
126 , "Punk"
127 , "Space"
128 , "Meditative"
129 , "Instrumental Pop"
130 , "Instrumental Rock"
131 , "Ethnic"
132 , "Gothic"
133 , "Darkwave"
134 , "Techno-Industrial"
135 , "Electronic"
136 , "Pop-Folk"
137 , "Eurodance"
138 , "Dream"
139 , "Southern Rock"
140 , "Comedy"
141 , "Cult"
142 , "Gangsta"
143 , "Top 40"
144 , "Christian Rap"
145 , "Pop/Funk"
146 , "Jungle"
147 , "Native American"
148 , "Cabaret"
149 , "New Wave"
150 , "Psychadelic"
151 , "Rave"
152 , "Showtunes"
153 , "Trailer"
154 , "Lo-Fi"
155 , "Tribal"
156 , "Acid Punk"
157 , "Acid Jazz"
158 , "Polka"
159 , "Retro"
160 , "Musical"
161 , "Rock & Roll"
162 , "Hard Rock"
163 , "Folk"
164 , "Folk-Rock"
165 , "National Folk"
166 , "Swing"
167 , "Fast Fusion"
168 , "Bebob"
169 , "Latin"
170 , "Revival"
171 , "Celtic"
172 , "Bluegrass"
173 , "Avantgarde"
174 , "Gothic Rock"
175 , "Progressive Rock"
176 , "Psychedelic Rock"
177 , "Symphonic Rock"
178 , "Slow Rock"
179 , "Big Band"
180 , "Chorus"
181 , "Easy Listening"
182 , "Acoustic"
183 , "Humour"
184 , "Speech"
185 , "Chanson"
186 , "Opera"
187 , "Chamber Music"
188 , "Sonata"
189 , "Symphony"
190 , "Booty Brass"
191 , "Primus"
192 , "Porn Groove"
193 , "Satire"
194 , "Slow Jam"
195 , "Club"
196 , "Tango"
197 , "Samba"
198 , "Folklore"
199 , "Ballad"
200 , "Power Ballad"
201 , "Rhythmic Soul"
202 , "Freestyle"
203 , "Duet"
204 , "Punk Rock"
205 , "Drum Solo"
206 , "A Capela"
207 , "Euro-House"
208 , "Dance Hall"
209 , "Goa"
210 , "Drum & Bass"
211 , "Club-House"
212 , "Hardcore"
213 , "Terror"
214 , "Indie"
215 , "BritPop"
216 , "Negerpunk"
217 , "Polsk Punk"
218 , "Beat"
219 , "Christian Gangsta Rap"
220 , "Heavy Metal"
221 , "Black Metal"
222 , "Crossover"
223 , "Contemporary Christian"
224 , "Christian Rock"
225 , "Merengue"
226 , "Salsa"
227 , "Thrash Metal"
228 , "Anime"
229 , "JPop"
230 , "SynthPop"
231 };
232
233 public MpegAudioFileReader()
234 {
235 super(MARK_LIMIT, true);
236 if (TDebug.TraceAudioFileReader) TDebug.out(">MpegAudioFileReader(1.9.2-FINAL)");
237 try
238 {
239 weak = System.getProperty("mp3spi.weak");
240 }
241 catch(AccessControlException e)
242 {}
243 }
244
245 /**
246 * Returns AudioFileFormat from File.
247 */
248 public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException
249 {
250 return super.getAudioFileFormat(file);
251 }
252
253 /**
254 * Returns AudioFileFormat from URL.
255 */
256 public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException
257 {
258 if (TDebug.TraceAudioFileReader) {TDebug.out("MpegAudioFileReader.getAudioFileFormat(URL): begin"); }
259 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
260 URLConnection conn = url.openConnection();
261 // Tell shoucast server (if any) that SPI support shoutcast stream.
262 conn.setRequestProperty ("Icy-Metadata", "1");
263 InputStream inputStream = conn.getInputStream();
264 AudioFileFormat audioFileFormat = null;
265 try
266 {
267 audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
268 }
269 finally
270 {
271 inputStream.close();
272 }
273 if (TDebug.TraceAudioFileReader) {TDebug.out("MpegAudioFileReader.getAudioFileFormat(URL): end"); }
274 return audioFileFormat;
275 }
276
277 /**
278 * Returns AudioFileFormat from inputstream and medialength.
279 */
280 public AudioFileFormat getAudioFileFormat(InputStream inputStream, long mediaLength) throws UnsupportedAudioFileException, IOException
281 {
282 if (TDebug.TraceAudioFileReader) TDebug.out(">MpegAudioFileReader.getAudioFileFormat(InputStream inputStream, long mediaLength): begin");
283 HashMap aff_properties = new HashMap();
284 HashMap af_properties = new HashMap();
285 int mLength = (int) mediaLength;
286 int size = inputStream.available();
287 PushbackInputStream pis = new PushbackInputStream(inputStream, MARK_LIMIT);
288 byte head[] = new byte[12];
289 pis.read(head);
290 if (TDebug.TraceAudioFileReader)
291 {
292 TDebug.out("InputStream : "+inputStream + " =>" + new String(head));
293 }
294 /*
295 * Check for WAV, AU, and AIFF file formats.
296 *
297 * Next check for Shoutcast (supported) and OGG (unsupported) streams.
298 *
299 * Note -- the check for WAV files will reject Broadcast WAV files.
300 * This may be incorrect as broadcast WAV files may contain MPEG data.
301 * Need to investigate.
302 *
303 */
304 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'))
305 {
306 if (TDebug.TraceAudioFileReader) TDebug.out("WAV stream found");
307 if (weak == null) throw new UnsupportedAudioFileException("WAV stream found");
308 }
309 else if ((head[0] == '.') && (head[1] == 's') && (head[2] == 'n') && (head[3] == 'd'))
310 {
311 if (TDebug.TraceAudioFileReader) TDebug.out("AU stream found");
312 if (weak == null) throw new UnsupportedAudioFileException("AU stream found");
313 }
314 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'))
315 {
316 if (TDebug.TraceAudioFileReader) TDebug.out("AIFF stream found");
317 if (weak == null) throw new UnsupportedAudioFileException("AIFF stream found");
318 }
319 // Shoutcast stream ?
320 else if (((head[0] == 'I') | (head[0] == 'i')) && ((head[1] == 'C') | (head[1] == 'c')) && ((head[2] == 'Y') | (head[2] == 'y')))
321 {
322 pis.unread(head);
323 // Load shoutcast meta data.
324 loadShoutcastInfo(pis, aff_properties);
325 }
326 // Ogg stream ?
327 else if (((head[0] == 'O') | (head[0] == 'o')) && ((head[1] == 'G') | (head[1] == 'g')) && ((head[2] == 'G') | (head[2] == 'g')))
328 {
329 if (TDebug.TraceAudioFileReader) TDebug.out("Ogg stream found");
330 if (weak == null) throw new UnsupportedAudioFileException("Ogg stream found");
331 }
332 // No, so pushback.
333 else
334 {
335 pis.unread(head);
336 }
337 // MPEG header info.
338 int nVersion = AudioSystem.NOT_SPECIFIED;
339 int nLayer = AudioSystem.NOT_SPECIFIED;
340 int nSFIndex = AudioSystem.NOT_SPECIFIED;
341 int nMode = AudioSystem.NOT_SPECIFIED;
342 int FrameSize = AudioSystem.NOT_SPECIFIED;
343 int nFrameSize = AudioSystem.NOT_SPECIFIED;
344 int nFrequency = AudioSystem.NOT_SPECIFIED;
345 int nTotalFrames = AudioSystem.NOT_SPECIFIED;
346 float FrameRate = AudioSystem.NOT_SPECIFIED;
347 int BitRate = AudioSystem.NOT_SPECIFIED;
348 int nChannels = AudioSystem.NOT_SPECIFIED;
349 int nHeader = AudioSystem.NOT_SPECIFIED;
350 int nTotalMS = AudioSystem.NOT_SPECIFIED;
351 boolean nVBR = false;
352 AudioFormat.Encoding encoding = null;
353 try
354 {
355 Bitstream m_bitstream = new Bitstream(pis);
356 aff_properties.put("mp3.header.pos",new Integer(m_bitstream.header_pos()));
357 Header m_header = m_bitstream.readFrame();
358 // nVersion = 0 => MPEG2-LSF (Including MPEG2.5), nVersion = 1 => MPEG1
359 nVersion = m_header.version();
360 if (nVersion == 2) aff_properties.put("mp3.version.mpeg",Float.toString(2.5f));
361 else aff_properties.put("mp3.version.mpeg",Integer.toString(2-nVersion));
362 // nLayer = 1,2,3
363 nLayer = m_header.layer();
364 aff_properties.put("mp3.version.layer",Integer.toString(nLayer));
365 nSFIndex = m_header.sample_frequency();
366 nMode = m_header.mode();
367 aff_properties.put("mp3.mode",new Integer(nMode));
368 nChannels = nMode == 3 ? 1 : 2;
369 aff_properties.put("mp3.channels",new Integer(nChannels));
370 nVBR = m_header.vbr();
371 af_properties.put("vbr",new Boolean(nVBR));
372 aff_properties.put("mp3.vbr",new Boolean(nVBR));
373 aff_properties.put("mp3.vbr.scale",new Integer(m_header.vbr_scale()));
374 FrameSize = m_header.calculate_framesize();
375 aff_properties.put("mp3.framesize.bytes",new Integer(FrameSize));
376 if (FrameSize < 0) throw new UnsupportedAudioFileException("Invalid FrameSize : " + FrameSize);
377 nFrequency = m_header.frequency();
378 aff_properties.put("mp3.frequency.hz",new Integer(nFrequency));
379 FrameRate = (float) ((1.0 / (m_header.ms_per_frame())) * 1000.0);
380 aff_properties.put("mp3.framerate.fps",new Float(FrameRate));
381 if (FrameRate < 0) throw new UnsupportedAudioFileException("Invalid FrameRate : " + FrameRate);
382 if (mLength != AudioSystem.NOT_SPECIFIED)
383 {
384 aff_properties.put("mp3.length.bytes",new Integer(mLength));
385 nTotalFrames = m_header.max_number_of_frames(mLength);
386 aff_properties.put("mp3.length.frames",new Integer(nTotalFrames));
387 }
388 BitRate = m_header.bitrate();
389 af_properties.put("bitrate",new Integer(BitRate));
390 aff_properties.put("mp3.bitrate.nominal.bps",new Integer(BitRate));
391 nHeader = m_header.getSyncHeader();
392 encoding = sm_aEncodings[nVersion][nLayer - 1];
393 aff_properties.put("mp3.version.encoding",encoding.toString());
394 if (mLength != AudioSystem.NOT_SPECIFIED)
395 {
396 nTotalMS = Math.round(m_header.total_ms(mLength));
397 aff_properties.put("duration",new Long((long)nTotalMS*1000L));
398 }
399 aff_properties.put("mp3.copyright",new Boolean(m_header.copyright()));
400 aff_properties.put("mp3.original",new Boolean(m_header.original()));
401 aff_properties.put("mp3.crc",new Boolean(m_header.checksums()));
402 aff_properties.put("mp3.padding",new Boolean(m_header.padding()));
403 InputStream id3v2 = m_bitstream.getRawID3v2();
404 if (id3v2 != null)
405 {
406 aff_properties.put("mp3.id3tag.v2",id3v2);
407 parseID3v2Frames(id3v2,aff_properties);
408 }
409 if (TDebug.TraceAudioFileReader) TDebug.out(m_header.toString());
410 }
411 catch (Exception e)
412 {
413 if (TDebug.TraceAudioFileReader) TDebug.out("not a MPEG stream:" + e.getMessage());
414 throw new UnsupportedAudioFileException("not a MPEG stream:" + e.getMessage());
415 }
416
417 // Deeper checks ?
418 int cVersion = (nHeader >> 19) & 0x3;
419 if (cVersion == 1)
420 {
421 if (TDebug.TraceAudioFileReader) TDebug.out("not a MPEG stream: wrong version");
422 throw new UnsupportedAudioFileException("not a MPEG stream: wrong version");
423 }
424
425 int cSFIndex = (nHeader >> 10) & 0x3;
426 if (cSFIndex == 3)
427 {
428 if (TDebug.TraceAudioFileReader) TDebug.out("not a MPEG stream: wrong sampling rate");
429 throw new UnsupportedAudioFileException("not a MPEG stream: wrong sampling rate");
430 }
431
432 // Look up for ID3v1 tag
433 if ((size == mediaLength) && (mediaLength != AudioSystem.NOT_SPECIFIED))
434 {
435 FileInputStream fis = (FileInputStream) inputStream;
436 byte[] id3v1 = new byte[128];
437 long bytesSkipped = fis.skip(inputStream.available()-id3v1.length);
438 int read = fis.read(id3v1,0,id3v1.length);
439 if ((id3v1[0]=='T') && (id3v1[1]=='A') && (id3v1[2]=='G'))
440 {
441 parseID3v1Frames(id3v1, aff_properties);
442 }
443 }
444
445 AudioFormat format = new MpegAudioFormat(encoding, (float) nFrequency, AudioSystem.NOT_SPECIFIED // SampleSizeInBits - The size of a sample
446 , nChannels // Channels - The number of channels
447 , -1 // The number of bytes in each frame
448 , FrameRate // FrameRate - The number of frames played or recorded per second
449 , true
450 , af_properties);
451 return new MpegAudioFileFormat(MpegFileFormatType.MP3, format, nTotalFrames, mLength,aff_properties);
452 }
453
454 /**
455 * Returns AudioInputStream from file.
456 */
457 public AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException
458 {
459 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(File file)");
460 InputStream inputStream = new FileInputStream(file);
461 try
462 {
463 return getAudioInputStream(inputStream);
464 }
465 catch (UnsupportedAudioFileException e)
466 {
467 if (inputStream != null) inputStream.close();
468 throw e;
469 }
470 catch (IOException e)
471 {
472 if (inputStream != null) inputStream.close();
473 throw e;
474 }
475 }
476
477 /**
478 * Returns AudioInputStream from url.
479 */
480 public AudioInputStream getAudioInputStream(URL url)
481 throws UnsupportedAudioFileException, IOException
482 {
483 if (TDebug.TraceAudioFileReader) {TDebug.out("MpegAudioFileReader.getAudioInputStream(URL): begin"); }
484 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
485 URLConnection conn = url.openConnection();
486 // Tell shoucast server (if any) that SPI support shoutcast stream.
487 boolean isShout = false;
488 int toRead=4;
489 byte[] head = new byte[toRead];
490
491 conn.setRequestProperty ("Icy-Metadata", "1");
492 BufferedInputStream bInputStream = new BufferedInputStream(conn.getInputStream());
493 bInputStream.mark(toRead);
494 int read = bInputStream.read(head,0,toRead);
495 if ((read>2) && (((head[0] == 'I') | (head[0] == 'i')) && ((head[1] == 'C') | (head[1] == 'c')) && ((head[2] == 'Y') | (head[2] == 'y')))) isShout = true;
496 bInputStream.reset();
497 InputStream inputStream = null;
498 // Is is a shoutcast server ?
499 if (isShout == true)
500 {
501 // Yes
502 IcyInputStream icyStream = new IcyInputStream(bInputStream);
503 icyStream.addTagParseListener(IcyListener.getInstance());
504 inputStream = icyStream;
505 }
506 else
507 {
508 // No, is Icecast 2 ?
509 String metaint = conn.getHeaderField("icy-metaint");
510 if (metaint != null)
511 {
512 // Yes, it might be icecast 2 mp3 stream.
513 IcyInputStream icyStream = new IcyInputStream(bInputStream,metaint);
514 icyStream.addTagParseListener(IcyListener.getInstance());
515 inputStream = icyStream;
516 }
517 else
518 {
519 // No
520 inputStream = bInputStream;
521 }
522 }
523 AudioInputStream audioInputStream = null;
524 try
525 {
526 audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
527 }
528 catch (UnsupportedAudioFileException e)
529 {
530 inputStream.close();
531 throw e;
532 }
533 catch (IOException e)
534 {
535 inputStream.close();
536 throw e;
537 }
538 if (TDebug.TraceAudioFileReader) {TDebug.out("MpegAudioFileReader.getAudioInputStream(URL): end"); }
539 return audioInputStream;
540 }
541
542 /**
543 * Return the AudioInputStream from the given InputStream.
544 */
545 public AudioInputStream getAudioInputStream(InputStream inputStream) throws UnsupportedAudioFileException, IOException
546 {
547 if (TDebug.TraceAudioFileReader) TDebug.out("MpegAudioFileReader.getAudioInputStream(InputStream inputStream)");
548 if (!inputStream.markSupported()) inputStream = new BufferedInputStream(inputStream);
549 return super.getAudioInputStream(inputStream);
550 }
551
552 /**
553 * Parser ID3v1 frames
554 * @param frames
555 * @param props
556 */
557 protected void parseID3v1Frames(byte[] frames, HashMap props)
558 {
559 if (TDebug.TraceAudioFileReader) TDebug.out("Parsing ID3v1");
560 String tag = null;
561 try
562 {
563 tag = new String(frames, 0, frames.length, "ISO-8859-1");
564 }
565 catch (UnsupportedEncodingException e)
566 {
567 tag = new String(frames, 0, frames.length);
568 if (TDebug.TraceAudioFileReader) TDebug.out("Cannot use ISO-8859-1");
569 }
570 if (TDebug.TraceAudioFileReader) TDebug.out("ID3v1 frame dump='"+tag+"'");
571 int start = 3;
572 String titlev1 = chopSubstring(tag, start, start += 30);
573 String titlev2 = (String) props.get("title");
574 if (((titlev2==null) || (titlev2.length()==0)) && (titlev1 != null)) props.put("title",titlev1);
575 String artistv1 = chopSubstring(tag, start, start += 30);
576 String artistv2 = (String) props.get("author");
577 if (((artistv2==null) || (artistv2.length()==0)) && (artistv1 != null)) props.put("author",artistv1);
578 String albumv1 = chopSubstring(tag, start, start += 30);
579 String albumv2 = (String) props.get("album");
580 if (((albumv2==null) || (albumv2.length()==0)) && (albumv1 != null)) props.put("album",albumv1);
581 String yearv1 = chopSubstring(tag, start, start += 4);
582 String yearv2 = (String) props.get("year");
583 if (((yearv2==null) || (yearv2.length()==0)) && (yearv1 != null)) props.put("date",yearv1);
584 String commentv1 = chopSubstring(tag, start, start += 28);
585 String commentv2 = (String) props.get("comment");
586 if (((commentv2==null) || (commentv2.length()==0)) && (commentv1 != null)) props.put("comment",commentv1);
587 String trackv1 = ""+((int) (frames[126] & 0xff));
588 String trackv2 = (String) props.get("mp3.id3tag.track");
589 if (((trackv2==null) || (trackv2.length()==0)) && (trackv1 != null)) props.put("mp3.id3tag.track",trackv1);
590
591 int genrev1 = (int) (frames[127] & 0xff);
592 if ((genrev1 >=0) && (genrev1<id3v1genres.length))
593 {
594 String genrev2 = (String) props.get("mp3.id3tag.genre");
595 if (((genrev2==null) || (genrev2.length()==0))) props.put("mp3.id3tag.genre",id3v1genres[genrev1]);
596 }
597 if (TDebug.TraceAudioFileReader) TDebug.out("ID3v1 parsed");
598 }
599
600 /**
601 * Extract
602 * @param s
603 * @param start
604 * @param end
605 * @return
606 */
607 private String chopSubstring(String s, int start, int end)
608 {
609 String str = null;
610 // 11/28/04 - String encoding bug fix.
611 try
612 {
613 str = s.substring(start, end);
614 int loc = str.indexOf('\0');
615 if (loc != -1) str = str.substring(0, loc);
616 }
617 catch (StringIndexOutOfBoundsException e)
618 {
619 // Skip encoding issues.
620 if (TDebug.TraceAudioFileReader) TDebug.out("Cannot chopSubString "+e.getMessage());
621 }
622 return str;
623 }
624 /**
625 * Parse ID3v2 frames to add album (TALB), title (TIT2), date (TYER), author (TPE1), copyright (TCOP), comment (COMM) ...
626 * @param frames
627 * @param props
628 */
629 protected void parseID3v2Frames(InputStream frames, HashMap props)
630 {
631 if (TDebug.TraceAudioFileReader) TDebug.out("Parsing ID3v2");
632 byte[] bframes = null;
633 int size = -1;
634 try
635 {
636 size = frames.available();
637 bframes = new byte[size];
638 frames.mark(size);
639 frames.read(bframes);
640 frames.reset();
641 }
642 catch (IOException e)
643 {
644 if (TDebug.TraceAudioFileReader) TDebug.out("Cannot parse ID3v2 :"+e.getMessage());
645 }
646
647 try
648 {
649 if (TDebug.TraceAudioFileReader) TDebug.out("ID3v2 frame dump='"+new String(bframes,0,bframes.length)+"'");
650 /* ID3 tags : http://www.unixgods.org/~tilo/ID3/docs/ID3_comparison.html */
651 String value = null;
652 for (int i=0;i<bframes.length-4;i++)
653 {
654 String code = new String(bframes,i,4);
655 String scode = new String(bframes,i,3);
656 // ID3v2.3 & v2.4
657 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")))
658 {
659 i=i+10;
660 size = (int) (bframes[i-6] << 24) + (bframes[i-5] << 16) + (bframes[i-4] << 8) + (bframes[i-3]);
661 if (code.equals("COMM")) value = parseText(bframes, i, size, 5);
662 else value = parseText(bframes,i, size, 1);
663 if ((value != null) && (value.length()>0))
664 {
665 if (code.equals("TALB")) props.put("album",value);
666 else if (code.equals("TIT2")) props.put("title",value);
667 else if (code.equals("TYER")) props.put("date",value);
668 // ID3v2.4 date fix.
669 else if (code.equals("TDRC")) props.put("date",value);
670 else if (code.equals("TPE1")) props.put("author",value);
671 else if (code.equals("TCOP")) props.put("copyright",value);
672 else if (code.equals("COMM")) props.put("comment",value);
673 else if (code.equals("TCON")) props.put("mp3.id3tag.genre",value);
674 else if (code.equals("TRCK")) props.put("mp3.id3tag.track",value);
675 else if (code.equals("TPOS")) props.put("mp3.id3tag.disc",value);
676 else if (code.equals("TCOM")) props.put("mp3.id3tag.composer",value);
677 else if (code.equals("TIT1")) props.put("mp3.id3tag.grouping",value);
678 else if (code.equals("TENC")) props.put("mp3.id3tag.encoded",value);
679 }
680 i=i+size-1;
681 }
682 // ID3v2.2.
683 else 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")))
684 {
685 i=i+6;
686 size = (int) (0x00000000) + (bframes[i-3] << 16) + (bframes[i-2] << 8) + (bframes[i-1]);
687 if (scode.equals("COM")) value = parseText(bframes, i, size, 5);
688 else value = parseText(bframes,i, size, 1);
689 if ((value != null) && (value.length()>0))
690 {
691 if (scode.equals("TAL")) props.put("album",value);
692 else if (scode.equals("TT2")) props.put("title",value);
693 else if (scode.equals("TYE")) props.put("date",value);
694 else if (scode.equals("TP1")) props.put("author",value);
695 else if (scode.equals("TCR")) props.put("copyright",value);
696 else if (scode.equals("COM")) props.put("comment",value);
697 else if (scode.equals("TCO")) props.put("mp3.id3tag.genre",value);
698 else if (scode.equals("TRK")) props.put("mp3.id3tag.track",value);
699 else if (scode.equals("TPA")) props.put("mp3.id3tag.disc",value);
700 else if (scode.equals("TCM")) props.put("mp3.id3tag.composer",value);
701 else if (scode.equals("TT1")) props.put("mp3.id3tag.grouping",value);
702 else if (scode.equals("TEN")) props.put("mp3.id3tag.encoded",value);
703 }
704 i=i+size-1;
705 }
706 else if (code.startsWith("ID3"))
707 {
708 // ID3v2 Header.
709 int v2version = (int) (bframes[3] & 0xFF);
710 props.put("mp3.id3tag.v2.version",String.valueOf(v2version));
711 i=i+4;
712 }
713 }
714 }
715 catch (RuntimeException e)
716 {
717 // Ignore all parsing errors.
718 if (TDebug.TraceAudioFileReader) TDebug.out("Cannot parse ID3v2 :"+e.getMessage());
719 }
720 if (TDebug.TraceAudioFileReader) TDebug.out("ID3v2 parsed");
721 }
722
723 /**
724 * Parse Text Frames.
725 * @param bframes
726 * @param offset
727 * @param size
728 * @param skip
729 * @return
730 */
731 protected String parseText(byte[] bframes, int offset, int size, int skip)
732 {
733 String value = null;
734 try
735 {
736 String[] ENC_TYPES = {"ISO-8859-1", "UTF16","UTF-16BE", "UTF-8"};
737 value = new String(bframes,offset+skip,size-skip,ENC_TYPES[bframes[offset]]);
738 value = chopSubstring(value,0,value.length());
739 }
740 catch (UnsupportedEncodingException e)
741 {
742 if (TDebug.TraceAudioFileReader) TDebug.out("ID3v2 Encoding error :"+e.getMessage());
743 }
744 return value;
745 }
746
747 /**
748 * Load shoutcast (ICY) info.
749 * @param input
750 * @param props
751 * @throws IOException
752 */
753 protected void loadShoutcastInfo(InputStream input, HashMap props) throws IOException
754 {
755 IcyInputStream icy = new IcyInputStream(new BufferedInputStream(input));
756 HashMap metadata = icy.getTagHash();
757 MP3Tag titleMP3Tag = icy.getTag("icy-name");
758 if (titleMP3Tag != null) props.put("title",((String) titleMP3Tag.getValue()).trim());
759 MP3Tag[] meta = icy.getTags();
760 if (meta != null)
761 {
762 StringBuffer metaStr = new StringBuffer();
763 for (int i=0;i<meta.length;i++)
764 {
765 String key = meta[i].getName();
766 String value = ((String) icy.getTag(key).getValue()).trim();
767 props.put("mp3.shoutcast.metadata."+key, value);
768 }
769 }
770 }
771
772} \ No newline at end of file
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFormat.java b/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFormat.java
deleted file mode 100644
index 29a66a3d93..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/file/MpegAudioFormat.java
+++ /dev/null
@@ -1,67 +0,0 @@
1/*
2 * MpegAudioFormat.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23
24package javazoom.spi.mpeg.sampled.file;
25
26import java.util.Map;
27
28import javax.sound.sampled.AudioFormat;
29
30import org.tritonus.share.sampled.TAudioFormat;
31
32/**
33 * @author JavaZOOM
34 */
35public class MpegAudioFormat extends TAudioFormat
36{
37 /**
38 * Constructor.
39 * @param encoding
40 * @param nFrequency
41 * @param SampleSizeInBits
42 * @param nChannels
43 * @param FrameSize
44 * @param FrameRate
45 * @param isBigEndian
46 * @param properties
47 */
48 public MpegAudioFormat(AudioFormat.Encoding encoding, float nFrequency, int SampleSizeInBits, int nChannels, int FrameSize, float FrameRate, boolean isBigEndian, Map properties)
49 {
50 super(encoding, nFrequency, SampleSizeInBits, nChannels, FrameSize, FrameRate, isBigEndian, properties);
51 }
52
53 /**
54 * MP3 audio format parameters.
55 * Some parameters might be unavailable. So availability test is required before reading any parameter.
56 *
57 * <br>AudioFormat parameters.
58 * <ul>
59 * <li><b>bitrate</b> [Integer], bitrate in bits per seconds, average bitrate for VBR enabled stream.
60 * <li><b>vbr</b> [Boolean], VBR flag.
61 * </ul>
62 */
63 public Map properties()
64 {
65 return super.properties();
66 }
67}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/MpegEncoding.java b/songdbj/javazoom/spi/mpeg/sampled/file/MpegEncoding.java
deleted file mode 100644
index 6306d9ec80..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/file/MpegEncoding.java
+++ /dev/null
@@ -1,47 +0,0 @@
1/*
2 * MpegEncoding.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23
24package javazoom.spi.mpeg.sampled.file;
25
26import javax.sound.sampled.AudioFormat;
27
28/**
29 * Encodings used by the MPEG audio decoder.
30 */
31public class MpegEncoding extends AudioFormat.Encoding
32{
33 public static final AudioFormat.Encoding MPEG1L1 = new MpegEncoding("MPEG1L1");
34 public static final AudioFormat.Encoding MPEG1L2 = new MpegEncoding("MPEG1L2");
35 public static final AudioFormat.Encoding MPEG1L3 = new MpegEncoding("MPEG1L3");
36 public static final AudioFormat.Encoding MPEG2L1 = new MpegEncoding("MPEG2L1");
37 public static final AudioFormat.Encoding MPEG2L2 = new MpegEncoding("MPEG2L2");
38 public static final AudioFormat.Encoding MPEG2L3 = new MpegEncoding("MPEG2L3");
39 public static final AudioFormat.Encoding MPEG2DOT5L1 = new MpegEncoding("MPEG2DOT5L1");
40 public static final AudioFormat.Encoding MPEG2DOT5L2 = new MpegEncoding("MPEG2DOT5L2");
41 public static final AudioFormat.Encoding MPEG2DOT5L3 = new MpegEncoding("MPEG2DOT5L3");
42
43 public MpegEncoding(String strName)
44 {
45 super(strName);
46 }
47}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/MpegFileFormatType.java b/songdbj/javazoom/spi/mpeg/sampled/file/MpegFileFormatType.java
deleted file mode 100644
index 2c59ad8621..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/file/MpegFileFormatType.java
+++ /dev/null
@@ -1,40 +0,0 @@
1/*
2 * MpegFileFormatType.
3 *
4 * JavaZOOM : mp3spi@javazoom.net
5 * http://www.javazoom.net
6 *
7 *-----------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *----------------------------------------------------------------------
22 */
23
24package javazoom.spi.mpeg.sampled.file;
25
26import javax.sound.sampled.AudioFileFormat;
27
28/**
29 * FileFormatTypes used by the MPEG audio decoder.
30 */
31public class MpegFileFormatType extends AudioFileFormat.Type
32{
33 public static final AudioFileFormat.Type MPEG = new MpegFileFormatType("MPEG", "mpeg");
34 public static final AudioFileFormat.Type MP3 = new MpegFileFormatType("MP3", "mp3");
35
36 public MpegFileFormatType(String strName, String strExtension)
37 {
38 super(strName, strExtension);
39 }
40}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyInputStream.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyInputStream.java
deleted file mode 100644
index 22aa4439fe..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyInputStream.java
+++ /dev/null
@@ -1,412 +0,0 @@
1/*
2 * IcyInputStream.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27
28import java.io.BufferedInputStream;
29import java.io.IOException;
30import java.io.InputStream;
31import java.net.URL;
32import java.net.URLConnection;
33import java.util.HashMap;
34import java.util.StringTokenizer;
35
36/** An BufferedInputStream that parses Shoutcast's "icy" metadata
37 from the stream. Gets headers at the beginning and if the
38 "icy-metaint" tag is found, it parses and strips in-stream
39 metadata.
40 <p>
41 <b>The deal with metaint</b>: Icy streams don't try to put
42 tags between MP3 frames the way that ID3 does. Instead, it
43 requires the client to strip metadata from the stream before
44 it hits the decoder. You get an
45 <code>icy-metaint</code> name/val in the beginning of the
46 stream iff you sent "Icy-Metadata" with value "1" in the
47 request headers (SimpleMP3DataSource does this if the
48 "parseStreamMetadata" boolean is true). If this is the case
49 then the value of icy-metaint is the amount of real data
50 between metadata blocks. Each block begins with an int
51 indicating how much metadata there is -- the block is this
52 value times 16 (it can be, and often is, 0).
53 <p>
54 Originally thought that "icy" implied Icecast, but this is
55 completely wrong -- real Icecast servers, found through
56 www.icecast.net and typified by URLs with a trailing directory
57 (like CalArts School of Music - http://65.165.174.100:8000/som)
58 do not have the "ICY 200 OK" magic string or any of the
59 CRLF-separated headers. Apparently, "icy" means "Shoutcast".
60 Yep, that's weird.
61 @author Chris Adamson, invalidname@mac.com
62 */
63public class IcyInputStream
64 extends BufferedInputStream
65 implements MP3MetadataParser {
66
67 public static boolean DEBUG = false;
68
69 MP3TagParseSupport tagParseSupport;
70 /** inline tags are delimited by ';', also filter out
71 null bytes
72 */
73 protected static final String INLINE_TAG_SEPARATORS = ";\u0000";
74 /* looks like icy streams start start with
75 ICY 200 OK\r\n
76 then the tags are like
77 icy-notice1:<BR>This stream requires <a href="http://www.winamp.com/">Winamp</a><BR>\r\n
78 icy-notice2:SHOUTcast Distributed Network Audio Server/win32 v1.8.2<BR>\r\n
79 icy-name:Core-upt Radio\r\n
80 icy-genre:Punk Ska Emo\r\n
81 icy-url:http://www.core-uptrecords.com\r\n
82 icy-pub:1\r\n
83 icy-metaint:8192\r\n
84 icy-br:56\r\n
85 \r\n (signifies end of headers)
86 we only get icy-metaint if the http request that created
87 this stream sent the header "icy-metadata:1"
88 //
89 in in-line metadata, we read a byte that tells us how
90 many 16-byte blocks there are (presumably, we still use
91 \r\n for the separator... the block is padded out with
92 0x00's that we can ignore)
93
94 // when server is full/down/etc, we get the following for
95 // one of the notice lines:
96 icy-notice2:This server has reached its user limit<BR>
97 or
98 icy-notice2:The resource requested is currently unavailable<BR>
99 */
100 /** Tags that have been discovered in the stream.
101 */
102 HashMap tags;
103 /** Buffer for readCRLF line... note this limits lines to
104 1024 chars (I've read that WinAmp barfs at 128, so
105 this is generous)
106 */
107 protected byte[] crlfBuffer = new byte[1024];
108 /** value of the "metaint" tag, which tells us how many bytes
109 of real data are between the metadata tags. if -1, this stream
110 does not have metadata after the header.
111 */
112 protected int metaint = -1;
113 /** how many bytes of real data remain before the next
114 block of metadata. Only meaningful if metaint != -1.
115 */
116 protected int bytesUntilNextMetadata = -1;
117 // TODO: comment for constructor
118 /** Reads the initial headers of the stream and adds
119 tags appropriatly. Gets set up to find, read,
120 and strip blocks of in-line metadata if the
121 <code>icy-metaint</code> header is found.
122 */
123 public IcyInputStream(InputStream in) throws IOException {
124 super(in);
125 tags = new HashMap();
126 tagParseSupport = new MP3TagParseSupport();
127 // read the initial tags here, including the metaint
128 // and set the counter for how far we read until
129 // the next metadata block (if any).
130 readInitialHeaders();
131 IcyTag metaIntTag = (IcyTag) getTag("icy-metaint");
132 if (DEBUG) System.out.println("METATAG:"+metaIntTag);
133 if (metaIntTag != null) {
134 String metaIntString = metaIntTag.getValueAsString();
135 try {
136 metaint = Integer.parseInt(metaIntString.trim());
137 if (DEBUG) System.out.println("METAINT:"+metaint);
138 bytesUntilNextMetadata = metaint;
139 }
140 catch (NumberFormatException nfe) {
141 }
142 }
143 }
144
145 /**
146 * IcyInputStream constructor for know meta-interval (Icecast 2)
147 * @param in
148 * @param metaint
149 * @throws IOException
150 */
151 public IcyInputStream(InputStream in, String metaIntString) throws IOException {
152 super(in);
153 tags = new HashMap();
154 tagParseSupport = new MP3TagParseSupport();
155 try
156 {
157 metaint = Integer.parseInt(metaIntString.trim());
158 if (DEBUG) System.out.println("METAINT:"+metaint);
159 bytesUntilNextMetadata = metaint;
160 }
161 catch (NumberFormatException nfe) {
162 }
163 }
164
165 /** Assuming we're at the top of the stream, read lines one
166 by one until we hit a completely blank \r\n. Parse the
167 data as IcyTags.
168 */
169 protected void readInitialHeaders() throws IOException {
170 String line = null;
171 while (!((line = readCRLFLine()).equals(""))) {
172 int colonIndex = line.indexOf(':');
173 // does it have a ':' separator
174 if (colonIndex == -1)
175 continue;
176 IcyTag tag =
177 new IcyTag(
178 line.substring(0, colonIndex),
179 line.substring(colonIndex + 1));
180 //System.out.println(tag);
181 addTag(tag);
182 }
183 }
184 /** Read everything up to the next CRLF, return it as
185 a String.
186 */
187 protected String readCRLFLine() throws IOException {
188 int i = 0;
189 for (; i < crlfBuffer.length; i++) {
190 byte aByte = (byte) read();
191 if (aByte == '\r') {
192 // possible end of line
193 byte anotherByte = (byte) read();
194 i++; // since we read again
195 if (anotherByte == '\n') {
196 break; // break out of while
197 }
198 else {
199 // oops, not end of line - put these in array
200 crlfBuffer[i - 1] = aByte;
201 crlfBuffer[i] = anotherByte;
202 }
203 }
204 else {
205 // if not \r
206 crlfBuffer[i] = aByte;
207 }
208 } // for
209 // get the string from the byte[]. i is 1 too high because of
210 // read-ahead in crlf block
211 return new String(crlfBuffer, 0, i - 1);
212 }
213 /** Reads and returns a single byte.
214 If the next byte is a metadata block, then that
215 block is read, stripped, and parsed before reading
216 and returning the first byte after the metadata block.
217 */
218 public int read() throws IOException {
219 if (bytesUntilNextMetadata > 0) {
220 bytesUntilNextMetadata--;
221 return super.read();
222 }
223 else if (bytesUntilNextMetadata == 0) {
224 // we need to read next metadata block
225 readMetadata();
226 bytesUntilNextMetadata = metaint - 1;
227 // -1 because we read byte on next line
228 return super.read();
229 }
230 else {
231 // no metadata in this stream
232 return super.read();
233 }
234 }
235 /** Reads a block of bytes. If the next byte is known
236 to be a block of metadata, then that is read, parsed,
237 and stripped, and then a block of bytes is read and
238 returned.
239 Otherwise, it may read up to but
240 not into the next metadata block if
241 <code>bytesUntilNextMetadata &lt; length</code>
242 */
243 public int read(byte[] buf, int offset, int length) throws IOException {
244 // if not on metadata, do the usual read so long as we
245 // don't read past metadata
246 if (bytesUntilNextMetadata > 0) {
247 int adjLength = Math.min(length, bytesUntilNextMetadata);
248 int got = super.read(buf, offset, adjLength);
249 bytesUntilNextMetadata -= got;
250 return got;
251 }
252 else if (bytesUntilNextMetadata == 0) {
253 // read/parse the metadata
254 readMetadata();
255 // now as above, except that we reset
256 // bytesUntilNextMetadata differently
257
258 //int adjLength = Math.min(length, bytesUntilNextMetadata);
259 //int got = super.read(buf, offset, adjLength);
260 //bytesUntilNextMetadata = metaint - got;
261
262 // Chop Fix - JavaZOOM (3 lines above seem buggy)
263 bytesUntilNextMetadata = metaint;
264 int adjLength = Math.min(length, bytesUntilNextMetadata);
265 int got = super.read(buf, offset, adjLength);
266 bytesUntilNextMetadata -= got;
267 // End fix - JavaZOOM
268
269
270 return got;
271 }
272 else {
273 // not even reading metadata
274 return super.read(buf, offset, length);
275 }
276 }
277 /** trivial <code>return read (buf, 0, buf.length)</code>
278 */
279 public int read(byte[] buf) throws IOException {
280 return read(buf, 0, buf.length);
281 }
282 /** Read the next segment of metadata. The stream <b>must</b>
283 be right on the segment, ie, the next byte to read is
284 the metadata block count. The metadata is parsed and
285 new tags are added with addTag(), which fires events
286 */
287 protected void readMetadata() throws IOException {
288 int blockCount = super.read();
289 if (DEBUG) System.out.println("BLOCKCOUNT:"+blockCount);
290 // System.out.println ("blocks to read: " + blockCount);
291 int byteCount = (blockCount * 16); // 16 bytes per block
292 if (byteCount < 0)
293 return; // WTF?!
294 byte[] metadataBlock = new byte[byteCount];
295 int index = 0;
296 // build an array of this metadata
297 while (byteCount > 0) {
298 int bytesRead = super.read(metadataBlock, index, byteCount);
299 index += bytesRead;
300 byteCount -= bytesRead;
301 }
302 // now parse it
303 if (blockCount > 0)
304 parseInlineIcyTags(metadataBlock);
305 } // readMetadata
306 /** Parse metadata from an in-stream "block" of bytes, add
307 a tag for each one.
308 <p>
309 Hilariously, the inline data format is totally different
310 than the top-of-stream header. For example, here's a
311 block I saw on "Final Fantasy Radio":
312 <pre>
313 StreamTitle='Final Fantasy 8 - Nobuo Uematsu - Blue Fields';StreamUrl='';
314 </pre>
315 In other words:
316 <ol>
317 <li>Tags are delimited by semicolons
318 <li>Keys/values are delimited by equals-signs
319 <li>Values are wrapped in single-quotes
320 <li>Key names are in SentenceCase, not lowercase-dashed
321 </ol>
322 */
323 protected void parseInlineIcyTags(byte[] tagBlock) {
324 String blockString = new String(tagBlock);
325 if (DEBUG) System.out.println("BLOCKSTR:"+blockString);
326 StringTokenizer izer =
327 new StringTokenizer(blockString, INLINE_TAG_SEPARATORS);
328 int i = 0;
329 while (izer.hasMoreTokens()) {
330 String tagString = izer.nextToken();
331 int separatorIdx = tagString.indexOf('=');
332 if (separatorIdx == -1)
333 continue; // bogus tagString if no '='
334 // try to strip single-quotes around value, if present
335 int valueStartIdx =
336 (tagString.charAt(separatorIdx + 1) == '\'')
337 ? separatorIdx + 2
338 : separatorIdx + 1;
339 int valueEndIdx =
340 (tagString.charAt(tagString.length() - 1)) == '\''
341 ? tagString.length() - 1
342 : tagString.length();
343 String name = tagString.substring(0, separatorIdx);
344 String value = tagString.substring(valueStartIdx, valueEndIdx);
345 // System.out.println (i++ + " " + name + ":" + value);
346 IcyTag tag = new IcyTag(name, value);
347 addTag(tag);
348 }
349 }
350 /** adds the tag to the HashMap of tags we have encountered
351 either in-stream or as headers, replacing any previous
352 tag with this name.
353 */
354 protected void addTag(IcyTag tag) {
355 tags.put(tag.getName(), tag);
356 // fire this as an event too
357 tagParseSupport.fireTagParsed(this, tag);
358 }
359 /** Get the named tag from the HashMap of headers and
360 in-line tags. Null if no such tag has been encountered.
361 */
362 public MP3Tag getTag(String tagName) {
363 return (MP3Tag) tags.get(tagName);
364 }
365 /** Get all tags (headers or in-stream) encountered thus far.
366 */
367 public MP3Tag[] getTags() {
368 return (MP3Tag[]) tags.values().toArray(new MP3Tag[0]);
369 }
370 /** Returns a HashMap of all headers and in-stream tags
371 parsed so far.
372 */
373 public HashMap getTagHash() {
374 return tags;
375 }
376 /** Adds a TagParseListener to be notified when this stream
377 parses MP3Tags.
378 */
379 public void addTagParseListener(TagParseListener tpl) {
380 tagParseSupport.addTagParseListener(tpl);
381 }
382 /** Removes a TagParseListener, so it won't be notified when
383 this stream parses MP3Tags.
384 */
385 public void removeTagParseListener(TagParseListener tpl) {
386 tagParseSupport.removeTagParseListener(tpl);
387 }
388 /** Quickie unit-test.
389 */
390 public static void main(String args[]) {
391 byte[] chow = new byte[200];
392 if (args.length != 1) {
393 //System.out.println("Usage: IcyInputStream <url>");
394 return;
395 }
396 try {
397 URL url = new URL(args[0]);
398 URLConnection conn = url.openConnection();
399 conn.setRequestProperty("Icy-Metadata", "1");
400 IcyInputStream icy =
401 new IcyInputStream(
402 new BufferedInputStream(conn.getInputStream()));
403 while (icy.available() > -1) {
404 // icy.read();
405 icy.read(chow, 0, chow.length);
406 }
407 }
408 catch (Exception e) {
409 e.printStackTrace();
410 }
411 }
412}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyTag.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyTag.java
deleted file mode 100644
index bbe70f1f3c..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/file/tag/IcyTag.java
+++ /dev/null
@@ -1,42 +0,0 @@
1/*
2 * IcyTag.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27/**
28 * A tag parsed from an icecast tag.
29 */
30public class IcyTag extends MP3Tag implements StringableTag {
31 /** Create a new tag, from the parsed name and (String) value.
32 It looks like all Icecast tags are Strings (safe to assume
33 this going forward?)
34 */
35 public IcyTag(String name, String stringValue) {
36 super(name, stringValue);
37 }
38 // so far as I know, all Icecast tags are strings
39 public String getValueAsString() {
40 return (String) getValue();
41 }
42}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3MetadataParser.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3MetadataParser.java
deleted file mode 100644
index 81511064b8..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3MetadataParser.java
+++ /dev/null
@@ -1,50 +0,0 @@
1/*
2 * MP3MetadataParser.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27
28/** An object that fires off TagParseEvents as they are parsed
29 from a stream, ServerSocket, or other metadata source
30 */
31public interface MP3MetadataParser {
32 /** Adds a TagParseListener to be notified when this object
33 parses MP3Tags.
34 */
35 public void addTagParseListener(TagParseListener tpl);
36 /** Removes a TagParseListener, so it won't be notified when
37 this object parses MP3Tags.
38 */
39 public void removeTagParseListener(TagParseListener tpl);
40 /** Get all tags (headers or in-stream) encountered thusfar.
41 This is included in this otherwise Listener-like scheme
42 because most standards are a mix of start-of-stream
43 metadata tags (like the http headers or the stuff at the
44 top of an ice stream) and inline data. Implementations should
45 hang onto all tags they parse and provide them with this
46 call. Callers should first use this call to get initial
47 tags, then subscribe for events as the stream continues.
48 */
49 public MP3Tag[] getTags();
50}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3Tag.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3Tag.java
deleted file mode 100644
index b545356240..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3Tag.java
+++ /dev/null
@@ -1,52 +0,0 @@
1/*
2 * MP3Tag.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27
28/** An individual piece of mp3 metadata, as a name/value pair.
29 Abstract just so that subclasses will indicate their
30 tagging scheme (Icy, ID3, etc.).
31 */
32public abstract class MP3Tag extends Object {
33 protected String name;
34 protected Object value;
35 public MP3Tag(String name, Object value) {
36 this.name = name;
37 this.value = value;
38 }
39 public String getName() {
40 return name;
41 }
42 public Object getValue() {
43 return value;
44 }
45 public String toString() {
46 return getClass().getName()
47 + " -- "
48 + getName()
49 + ":"
50 + getValue().toString();
51 }
52}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3TagParseSupport.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3TagParseSupport.java
deleted file mode 100644
index 1ab6525512..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/file/tag/MP3TagParseSupport.java
+++ /dev/null
@@ -1,62 +0,0 @@
1/*
2 * MP3TagParseSupport.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27
28import java.util.ArrayList;
29/**
30*/
31public class MP3TagParseSupport extends Object {
32 ArrayList tagParseListeners;
33 /** trivial constructor, sets up listeners list.
34 */
35 public MP3TagParseSupport() {
36 super();
37 tagParseListeners = new ArrayList();
38 }
39 /** Adds a TagParseListener to be notified when a stream
40 parses MP3Tags.
41 */
42 public void addTagParseListener(TagParseListener tpl) {
43 tagParseListeners.add(tpl);
44 }
45 /** Removes a TagParseListener, so it won't be notified when
46 a stream parses MP3Tags.
47 */
48 public void removeTagParseListener(TagParseListener tpl) {
49 tagParseListeners.add(tpl);
50 }
51 /** Fires the given event to all registered listeners
52 */
53 public void fireTagParseEvent(TagParseEvent tpe) {
54 for (int i = 0; i < tagParseListeners.size(); i++) {
55 TagParseListener l = (TagParseListener) tagParseListeners.get(i);
56 l.tagParsed(tpe);
57 }
58 }
59 public void fireTagParsed(Object source, MP3Tag tag) {
60 fireTagParseEvent(new TagParseEvent(source, tag));
61 }
62}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/StringableTag.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/StringableTag.java
deleted file mode 100644
index 685c5207f9..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/file/tag/StringableTag.java
+++ /dev/null
@@ -1,36 +0,0 @@
1/*
2 * StringableTag.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27
28/** Indicates that the value of a tag is a string, and
29 provides a getValueAsString() method to get it.
30 Appropriate for tags like artist, title, etc.
31 */
32public interface StringableTag {
33 /** Return the value of this tag as a string.
34 */
35 public String getValueAsString();
36}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseEvent.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseEvent.java
deleted file mode 100644
index 97e9ec1e19..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseEvent.java
+++ /dev/null
@@ -1,44 +0,0 @@
1/*
2 * TagParseEvent.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27
28import java.util.EventObject;
29/** Event to indicate that an MP3 tag was received through
30 some means (parsed in stream, received via UDP, whatever)
31 and converted into an MP3Tag object.
32 */
33public class TagParseEvent extends EventObject {
34 protected MP3Tag tag;
35 public TagParseEvent(Object source, MP3Tag tag) {
36 super(source);
37 this.tag = tag;
38 }
39 /** Get the tag that was parsed.
40 */
41 public MP3Tag getTag() {
42 return tag;
43 }
44}
diff --git a/songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseListener.java b/songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseListener.java
deleted file mode 100644
index a630827297..0000000000
--- a/songdbj/javazoom/spi/mpeg/sampled/file/tag/TagParseListener.java
+++ /dev/null
@@ -1,37 +0,0 @@
1/*
2 * TagParseListener.
3 *
4 * jicyshout : http://sourceforge.net/projects/jicyshout/
5 *
6 * JavaZOOM : mp3spi@javazoom.net
7 * http://www.javazoom.net
8 *
9 *-----------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------
24 */
25
26package javazoom.spi.mpeg.sampled.file.tag;
27
28import java.util.EventListener;
29/** EventListener to be implemented by objects that want to
30 get callbacks when MP3 tags are received.
31 */
32public interface TagParseListener extends EventListener {
33 /** Called when a tag is found (parsed from the stream,
34 received via UDP, etc.)
35 */
36 public void tagParsed(TagParseEvent tpe);
37}
diff --git a/songdbj/javazoom/spi/vorbis/sampled/convert/DecodedVorbisAudioInputStream.java b/songdbj/javazoom/spi/vorbis/sampled/convert/DecodedVorbisAudioInputStream.java
deleted file mode 100644
index b8e8577e13..0000000000
--- a/songdbj/javazoom/spi/vorbis/sampled/convert/DecodedVorbisAudioInputStream.java
+++ /dev/null
@@ -1,519 +0,0 @@
1/*
2 * DecodedVorbisAudioInputStream
3 *
4 * JavaZOOM : vorbisspi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * ----------------------------------------------------------------------------
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * ----------------------------------------------------------------------------
22 */
23
24package javazoom.spi.vorbis.sampled.convert;
25
26import java.io.IOException;
27import java.io.InputStream;
28import java.util.HashMap;
29import java.util.Map;
30
31import javax.sound.sampled.AudioFormat;
32import javax.sound.sampled.AudioInputStream;
33
34import javazoom.spi.PropertiesContainer;
35
36import org.tritonus.share.TDebug;
37import org.tritonus.share.sampled.convert.TAsynchronousFilteredAudioInputStream;
38
39import com.jcraft.jogg.Packet;
40import com.jcraft.jogg.Page;
41import com.jcraft.jogg.StreamState;
42import com.jcraft.jogg.SyncState;
43import com.jcraft.jorbis.Block;
44import com.jcraft.jorbis.Comment;
45import com.jcraft.jorbis.DspState;
46import com.jcraft.jorbis.Info;
47
48/**
49 * This class implements the Vorbis decoding.
50 */
51public class DecodedVorbisAudioInputStream extends TAsynchronousFilteredAudioInputStream implements PropertiesContainer
52{
53 private InputStream oggBitStream_ = null;
54
55 private SyncState oggSyncState_ = null;
56 private StreamState oggStreamState_ = null;
57 private Page oggPage_ = null;
58 private Packet oggPacket_ = null;
59 private Info vorbisInfo = null;
60 private Comment vorbisComment = null;
61 private DspState vorbisDspState = null;
62 private Block vorbisBlock = null;
63
64 static final int playState_NeedHeaders = 0;
65 static final int playState_ReadData = 1;
66 static final int playState_WriteData = 2;
67 static final int playState_Done = 3;
68 static final int playState_BufferFull = 4;
69 static final int playState_Corrupt = -1;
70 private int playState;
71
72 private int bufferMultiple_ = 4;
73 private int bufferSize_ = bufferMultiple_ * 256 * 2;
74 private int convsize = bufferSize_ * 2;
75 private byte[] convbuffer = new byte[convsize];
76 private byte[] buffer = null;
77 private int bytes = 0;
78 private float[][][] _pcmf = null;
79 private int[] _index = null;
80 private int index = 0;
81 private int i = 0;
82 // bout is now a global so that we can continue from when we have a buffer full.
83 int bout = 0;
84
85 private HashMap properties = null;
86 private long currentBytes = 0;
87
88 /**
89 * Constructor.
90 */
91 public DecodedVorbisAudioInputStream(AudioFormat outputFormat, AudioInputStream bitStream)
92 {
93 super(outputFormat, -1);
94 this.oggBitStream_ = bitStream;
95 init_jorbis();
96 index = 0;
97 playState = playState_NeedHeaders;
98 properties = new HashMap();
99 }
100
101 /**
102 * Initializes all the jOrbis and jOgg vars that are used for song playback.
103 */
104 private void init_jorbis()
105 {
106 oggSyncState_ = new SyncState();
107 oggStreamState_ = new StreamState();
108 oggPage_ = new Page();
109 oggPacket_ = new Packet();
110 vorbisInfo = new Info();
111 vorbisComment = new Comment();
112 vorbisDspState = new DspState();
113 vorbisBlock = new Block(vorbisDspState);
114 buffer = null;
115 bytes = 0;
116 currentBytes = 0L;
117 oggSyncState_.init();
118 }
119
120 /**
121 * Return dynamic properties.
122 *
123 * <ul>
124 * <li><b>ogg.position.byte</b> [Long], current position in bytes in the stream.
125 *</ul>
126 */
127 public Map properties()
128 {
129 properties.put("ogg.position.byte",new Long(currentBytes));
130 return properties;
131 }
132 /**
133 * Main loop.
134 */
135 public void execute()
136 {
137 if(TDebug.TraceAudioConverter)
138 {
139 switch(playState)
140 {
141 case playState_NeedHeaders:
142 TDebug.out("playState = playState_NeedHeaders");
143 break;
144 case playState_ReadData:
145 TDebug.out("playState = playState_ReadData");
146 break;
147 case playState_WriteData:
148 TDebug.out("playState = playState_WriteData");
149 break;
150 case playState_Done:
151 TDebug.out("playState = playState_Done");
152 break;
153 case playState_BufferFull:
154 TDebug.out("playState = playState_BufferFull");
155 break;
156 case playState_Corrupt:
157 TDebug.out("playState = playState_Corrupt");
158 break;
159 }
160 }
161 // This code was developed by the jCraft group, as JOrbisPlayer.java, slightly
162 // modified by jOggPlayer developer and adapted by JavaZOOM to suit the JavaSound
163 // SPI. Then further modified by Tom Kimpton to correctly play ogg files that
164 // would hang the player.
165 switch(playState)
166 {
167 case playState_NeedHeaders:
168 try
169 {
170 // Headers (+ Comments).
171 readHeaders();
172 }
173 catch(IOException ioe)
174 {
175 playState = playState_Corrupt;
176 return;
177 }
178 playState = playState_ReadData;
179 break;
180
181 case playState_ReadData:
182 int result;
183 index = oggSyncState_.buffer(bufferSize_);
184 buffer = oggSyncState_.data;
185 bytes = readFromStream(buffer, index, bufferSize_);
186 if(TDebug.TraceAudioConverter) TDebug.out("More data : " + bytes);
187 if(bytes == -1)
188 {
189 playState = playState_Done;
190 if(TDebug.TraceAudioConverter) TDebug.out("Ogg Stream empty. Settings playState to playState_Done.");
191 break;
192 }
193 else
194 {
195 oggSyncState_.wrote(bytes);
196 if(bytes == 0)
197 {
198 if((oggPage_.eos() != 0) || (oggStreamState_.e_o_s != 0) || (oggPacket_.e_o_s != 0))
199 {
200 if(TDebug.TraceAudioConverter) TDebug.out("oggSyncState wrote 0 bytes: settings playState to playState_Done.");
201 playState = playState_Done;
202 }
203 if(TDebug.TraceAudioConverter) TDebug.out("oggSyncState wrote 0 bytes: but stream not yet empty.");
204 break;
205 }
206 }
207
208 result = oggSyncState_.pageout(oggPage_);
209 if(result == 0)
210 {
211 if(TDebug.TraceAudioConverter) TDebug.out("Setting playState to playState_ReadData.");
212 playState = playState_ReadData;
213 break;
214 } // need more data
215 if(result == -1)
216 { // missing or corrupt data at this page position
217 if(TDebug.TraceAudioConverter) TDebug.out("Corrupt or missing data in bitstream; setting playState to playState_ReadData");
218 playState = playState_ReadData;
219 break;
220 }
221
222 oggStreamState_.pagein(oggPage_);
223
224 if(TDebug.TraceAudioConverter) TDebug.out("Setting playState to playState_WriteData.");
225 playState = playState_WriteData;
226 break;
227
228 case playState_WriteData:
229 // Decoding !
230 if(TDebug.TraceAudioConverter) TDebug.out("Decoding");
231 while(true)
232 {
233 result = oggStreamState_.packetout(oggPacket_);
234 if(result == 0)
235 {
236 if(TDebug.TraceAudioConverter) TDebug.out("Packetout returned 0, going to read state.");
237 playState = playState_ReadData;
238 break;
239 } // need more data
240 else if(result == -1)
241 {
242 // missing or corrupt data at this page position
243 // no reason to complain; already complained above
244 if(TDebug.TraceAudioConverter) TDebug.out("Corrupt or missing data in packetout bitstream; going to read state...");
245 // playState = playState_ReadData;
246 // break;
247 continue;
248 }
249 else
250 {
251 // we have a packet. Decode it
252 if(vorbisBlock.synthesis(oggPacket_) == 0)
253 { // test for success!
254 vorbisDspState.synthesis_blockin(vorbisBlock);
255 }
256 else
257 {
258 //if(TDebug.TraceAudioConverter) TDebug.out("vorbisBlock.synthesis() returned !0, going to read state");
259 if(TDebug.TraceAudioConverter) TDebug.out("VorbisBlock.synthesis() returned !0, continuing.");
260 continue;
261 }
262
263 outputSamples();
264 if(playState == playState_BufferFull)
265 return;
266
267 } // else result != -1
268 } // while(true)
269 if(oggPage_.eos() != 0)
270 {
271 if(TDebug.TraceAudioConverter) TDebug.out("Settings playState to playState_Done.");
272 playState = playState_Done;
273 }
274 break;
275 case playState_BufferFull:
276 continueFromBufferFull();
277 break;
278
279 case playState_Corrupt:
280 if(TDebug.TraceAudioConverter) TDebug.out("Corrupt Song.");
281 // drop through to playState_Done...
282 case playState_Done:
283 oggStreamState_.clear();
284 vorbisBlock.clear();
285 vorbisDspState.clear();
286 vorbisInfo.clear();
287 oggSyncState_.clear();
288 if(TDebug.TraceAudioConverter) TDebug.out("Done Song.");
289 try
290 {
291 if(oggBitStream_ != null)
292 {
293 oggBitStream_.close();
294 }
295 getCircularBuffer().close();
296 }
297 catch(Exception e)
298 {
299 if(TDebug.TraceAudioConverter) TDebug.out(e.getMessage());
300 }
301 break;
302 } // switch
303 }
304
305 /**
306 * This routine was extracted so that when the output buffer fills up,
307 * we can break out of the loop, let the music channel drain, then
308 * continue from where we were.
309 */
310 private void outputSamples()
311 {
312 int samples;
313 while((samples = vorbisDspState.synthesis_pcmout(_pcmf, _index)) > 0)
314 {
315 float[][] pcmf = _pcmf[0];
316 bout = (samples < convsize ? samples : convsize);
317 double fVal = 0.0;
318 // convert doubles to 16 bit signed ints (host order) and
319 // interleave
320 for(i = 0; i < vorbisInfo.channels; i++)
321 {
322 int pointer = i * 2;
323 //int ptr=i;
324 int mono = _index[i];
325 for(int j = 0; j < bout; j++)
326 {
327 fVal = pcmf[i][mono + j] * 32767.;
328 int val = (int) (fVal);
329 if(val > 32767)
330 {
331 val = 32767;
332 }
333 if(val < -32768)
334 {
335 val = -32768;
336 }
337 if(val < 0)
338 {
339 val = val | 0x8000;
340 }
341 convbuffer[pointer] = (byte) (val);
342 convbuffer[pointer + 1] = (byte) (val >>> 8);
343 pointer += 2 * (vorbisInfo.channels);
344 }
345 }
346 if(TDebug.TraceAudioConverter) TDebug.out("about to write: " + 2 * vorbisInfo.channels * bout);
347 if(getCircularBuffer().availableWrite() < 2 * vorbisInfo.channels * bout)
348 {
349 if(TDebug.TraceAudioConverter) TDebug.out("Too much data in this data packet, better return, let the channel drain, and try again...");
350 playState = playState_BufferFull;
351 return;
352 }
353 getCircularBuffer().write(convbuffer, 0, 2 * vorbisInfo.channels * bout);
354 if(bytes < bufferSize_)
355 if(TDebug.TraceAudioConverter) TDebug.out("Finished with final buffer of music?");
356 if(vorbisDspState.synthesis_read(bout) != 0)
357 {
358 if(TDebug.TraceAudioConverter) TDebug.out("VorbisDspState.synthesis_read returned -1.");
359 }
360 } // while(samples...)
361 playState = playState_ReadData;
362 }
363
364 private void continueFromBufferFull()
365 {
366 if(getCircularBuffer().availableWrite() < 2 * vorbisInfo.channels * bout)
367 {
368 if(TDebug.TraceAudioConverter) TDebug.out("Too much data in this data packet, better return, let the channel drain, and try again...");
369 // Don't change play state.
370 return;
371 }
372 getCircularBuffer().write(convbuffer, 0, 2 * vorbisInfo.channels * bout);
373 // Don't change play state. Let outputSamples change play state, if necessary.
374 outputSamples();
375 }
376 /**
377 * Reads headers and comments.
378 */
379 private void readHeaders() throws IOException
380 {
381 if(TDebug.TraceAudioConverter) TDebug.out("readHeaders(");
382 index = oggSyncState_.buffer(bufferSize_);
383 buffer = oggSyncState_.data;
384 bytes = readFromStream(buffer, index, bufferSize_);
385 if(bytes == -1)
386 {
387 if(TDebug.TraceAudioConverter) TDebug.out("Cannot get any data from selected Ogg bitstream.");
388 throw new IOException("Cannot get any data from selected Ogg bitstream.");
389 }
390 oggSyncState_.wrote(bytes);
391 if(oggSyncState_.pageout(oggPage_) != 1)
392 {
393 if(bytes < bufferSize_)
394 {
395 throw new IOException("EOF");
396 }
397 if(TDebug.TraceAudioConverter) TDebug.out("Input does not appear to be an Ogg bitstream.");
398 throw new IOException("Input does not appear to be an Ogg bitstream.");
399 }
400 oggStreamState_.init(oggPage_.serialno());
401 vorbisInfo.init();
402 vorbisComment.init();
403 if(oggStreamState_.pagein(oggPage_) < 0)
404 {
405 // error; stream version mismatch perhaps
406 if(TDebug.TraceAudioConverter) TDebug.out("Error reading first page of Ogg bitstream data.");
407 throw new IOException("Error reading first page of Ogg bitstream data.");
408 }
409 if(oggStreamState_.packetout(oggPacket_) != 1)
410 {
411 // no page? must not be vorbis
412 if(TDebug.TraceAudioConverter) TDebug.out("Error reading initial header packet.");
413 throw new IOException("Error reading initial header packet.");
414 }
415 if(vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_) < 0)
416 {
417 // error case; not a vorbis header
418 if(TDebug.TraceAudioConverter) TDebug.out("This Ogg bitstream does not contain Vorbis audio data.");
419 throw new IOException("This Ogg bitstream does not contain Vorbis audio data.");
420 }
421 //int i = 0;
422 i = 0;
423 while(i < 2)
424 {
425 while(i < 2)
426 {
427 int result = oggSyncState_.pageout(oggPage_);
428 if(result == 0)
429 {
430 break;
431 } // Need more data
432 if(result == 1)
433 {
434 oggStreamState_.pagein(oggPage_);
435 while(i < 2)
436 {
437 result = oggStreamState_.packetout(oggPacket_);
438 if(result == 0)
439 {
440 break;
441 }
442 if(result == -1)
443 {
444 if(TDebug.TraceAudioConverter) TDebug.out("Corrupt secondary header. Exiting.");
445 throw new IOException("Corrupt secondary header. Exiting.");
446 }
447 vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_);
448 i++;
449 }
450 }
451 }
452 index = oggSyncState_.buffer(bufferSize_);
453 buffer = oggSyncState_.data;
454 bytes = readFromStream(buffer, index, bufferSize_);
455 if(bytes == -1)
456 {
457 break;
458 }
459 if(bytes == 0 && i < 2)
460 {
461 if(TDebug.TraceAudioConverter) TDebug.out("End of file before finding all Vorbis headers!");
462 throw new IOException("End of file before finding all Vorbis headers!");
463 }
464 oggSyncState_.wrote(bytes);
465 }
466
467 byte[][] ptr = vorbisComment.user_comments;
468 String currComment = "";
469
470 for(int j = 0; j < ptr.length; j++)
471 {
472 if(ptr[j] == null)
473 {
474 break;
475 }
476 currComment = (new String(ptr[j], 0, ptr[j].length - 1)).trim();
477 if(TDebug.TraceAudioConverter) TDebug.out("Comment: " + currComment);
478 }
479 convsize = bufferSize_ / vorbisInfo.channels;
480 vorbisDspState.synthesis_init(vorbisInfo);
481 vorbisBlock.init(vorbisDspState);
482 _pcmf = new float[1][][];
483 _index = new int[vorbisInfo.channels];
484 }
485
486 /**
487 * Reads from the oggBitStream_ a specified number of Bytes(bufferSize_) worth
488 * starting at index and puts them in the specified buffer[].
489 *
490 * @param buffer
491 * @param index
492 * @param bufferSize_
493 * @return the number of bytes read or -1 if error.
494 */
495 private int readFromStream(byte[] buffer, int index, int bufferSize_)
496 {
497 int bytes = 0;
498 try
499 {
500 bytes = oggBitStream_.read(buffer, index, bufferSize_);
501 }
502 catch(Exception e)
503 {
504 if(TDebug.TraceAudioConverter) TDebug.out("Cannot Read Selected Song");
505 bytes = -1;
506 }
507 currentBytes = currentBytes + bytes;
508 return bytes;
509 }
510
511 /**
512 * Close the stream.
513 */
514 public void close() throws IOException
515 {
516 super.close();
517 oggBitStream_.close();
518 }
519}
diff --git a/songdbj/javazoom/spi/vorbis/sampled/convert/VorbisFormatConversionProvider.java b/songdbj/javazoom/spi/vorbis/sampled/convert/VorbisFormatConversionProvider.java
deleted file mode 100644
index d1321f2590..0000000000
--- a/songdbj/javazoom/spi/vorbis/sampled/convert/VorbisFormatConversionProvider.java
+++ /dev/null
@@ -1,244 +0,0 @@
1/*
2 * VorbisFormatConversionProvider.
3 *
4 * JavaZOOM : vorbisspi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23package javazoom.spi.vorbis.sampled.convert;
24
25import java.util.Arrays;
26import javazoom.spi.vorbis.sampled.file.VorbisEncoding;
27import javax.sound.sampled.AudioFormat;
28import javax.sound.sampled.AudioInputStream;
29
30import org.tritonus.share.sampled.convert.TMatrixFormatConversionProvider;
31
32/**
33 * ConversionProvider for VORBIS files.
34 */
35public class VorbisFormatConversionProvider extends TMatrixFormatConversionProvider
36{
37 private static final AudioFormat[] INPUT_FORMATS =
38 {
39 new AudioFormat(VorbisEncoding.VORBISENC, 32000.0F, -1, 1, -1, -1, false), // 0
40 new AudioFormat(VorbisEncoding.VORBISENC, 32000.0F, -1, 2, -1, -1, false), // 1
41 new AudioFormat(VorbisEncoding.VORBISENC, 44100.0F, -1, 1, -1, -1, false), // 2
42 new AudioFormat(VorbisEncoding.VORBISENC, 44100.0F, -1, 2, -1, -1, false), // 3
43 new AudioFormat(VorbisEncoding.VORBISENC, 48000.0F, -1, 1, -1, -1, false), // 4
44 new AudioFormat(VorbisEncoding.VORBISENC, 48000.0F, -1, 2, -1, -1, false), // 5
45
46 new AudioFormat(VorbisEncoding.VORBISENC, 16000.0F, -1, 1, -1, -1, false), // 18
47 new AudioFormat(VorbisEncoding.VORBISENC, 16000.0F, -1, 2, -1, -1, false), // 19
48 new AudioFormat(VorbisEncoding.VORBISENC, 22050.0F, -1, 1, -1, -1, false), // 20
49 new AudioFormat(VorbisEncoding.VORBISENC, 22050.0F, -1, 2, -1, -1, false), // 21
50 new AudioFormat(VorbisEncoding.VORBISENC, 24000.0F, -1, 1, -1, -1, false), // 22
51 new AudioFormat(VorbisEncoding.VORBISENC, 24000.0F, -1, 2, -1, -1, false), // 23
52
53 new AudioFormat(VorbisEncoding.VORBISENC, 8000.0F, -1, 1, -1, -1, false), // 36
54 new AudioFormat(VorbisEncoding.VORBISENC, 8000.0F, -1, 2, -1, -1, false), // 37
55 new AudioFormat(VorbisEncoding.VORBISENC, 11025.0F, -1, 1, -1, -1, false), // 38
56 new AudioFormat(VorbisEncoding.VORBISENC, 11025.0F, -1, 2, -1, -1, false), // 39
57 new AudioFormat(VorbisEncoding.VORBISENC, 12000.0F, -1, 1, -1, -1, false), // 40
58 new AudioFormat(VorbisEncoding.VORBISENC, 12000.0F, -1, 2, -1, -1, false), // 41
59 };
60
61 private static final AudioFormat[] OUTPUT_FORMATS =
62 {
63 new AudioFormat(8000.0F, 16, 1, true, false), // 0
64 new AudioFormat(8000.0F, 16, 1, true, true), // 1
65 new AudioFormat(8000.0F, 16, 2, true, false), // 2
66 new AudioFormat(8000.0F, 16, 2, true, true), // 3
67 /* 24 and 32 bit not yet possible
68 new AudioFormat(8000.0F, 24, 1, true, false),
69 new AudioFormat(8000.0F, 24, 1, true, true),
70 new AudioFormat(8000.0F, 24, 2, true, false),
71 new AudioFormat(8000.0F, 24, 2, true, true),
72 new AudioFormat(8000.0F, 32, 1, true, false),
73 new AudioFormat(8000.0F, 32, 1, true, true),
74 new AudioFormat(8000.0F, 32, 2, true, false),
75 new AudioFormat(8000.0F, 32, 2, true, true),
76 */
77 new AudioFormat(11025.0F, 16, 1, true, false), // 4
78 new AudioFormat(11025.0F, 16, 1, true, true), // 5
79 new AudioFormat(11025.0F, 16, 2, true, false), // 6
80 new AudioFormat(11025.0F, 16, 2, true, true), // 7
81 /* 24 and 32 bit not yet possible
82 new AudioFormat(11025.0F, 24, 1, true, false),
83 new AudioFormat(11025.0F, 24, 1, true, true),
84 new AudioFormat(11025.0F, 24, 2, true, false),
85 new AudioFormat(11025.0F, 24, 2, true, true),
86 new AudioFormat(11025.0F, 32, 1, true, false),
87 new AudioFormat(11025.0F, 32, 1, true, true),
88 new AudioFormat(11025.0F, 32, 2, true, false),
89 new AudioFormat(11025.0F, 32, 2, true, true),
90 */
91 new AudioFormat(12000.0F, 16, 1, true, false), // 8
92 new AudioFormat(12000.0F, 16, 1, true, true), // 9
93 new AudioFormat(12000.0F, 16, 2, true, false), // 10
94 new AudioFormat(12000.0F, 16, 2, true, true), // 11
95 /* 24 and 32 bit not yet possible
96 new AudioFormat(12000.0F, 24, 1, true, false),
97 new AudioFormat(12000.0F, 24, 1, true, true),
98 new AudioFormat(12000.0F, 24, 2, true, false),
99 new AudioFormat(12000.0F, 24, 2, true, true),
100 new AudioFormat(12000.0F, 32, 1, true, false),
101 new AudioFormat(12000.0F, 32, 1, true, true),
102 new AudioFormat(12000.0F, 32, 2, true, false),
103 new AudioFormat(12000.0F, 32, 2, true, true),
104 */
105 new AudioFormat(16000.0F, 16, 1, true, false), // 12
106 new AudioFormat(16000.0F, 16, 1, true, true), // 13
107 new AudioFormat(16000.0F, 16, 2, true, false), // 14
108 new AudioFormat(16000.0F, 16, 2, true, true), // 15
109 /* 24 and 32 bit not yet possible
110 new AudioFormat(16000.0F, 24, 1, true, false),
111 new AudioFormat(16000.0F, 24, 1, true, true),
112 new AudioFormat(16000.0F, 24, 2, true, false),
113 new AudioFormat(16000.0F, 24, 2, true, true),
114 new AudioFormat(16000.0F, 32, 1, true, false),
115 new AudioFormat(16000.0F, 32, 1, true, true),
116 new AudioFormat(16000.0F, 32, 2, true, false),
117 new AudioFormat(16000.0F, 32, 2, true, true),
118 */
119 new AudioFormat(22050.0F, 16, 1, true, false), // 16
120 new AudioFormat(22050.0F, 16, 1, true, true), // 17
121 new AudioFormat(22050.0F, 16, 2, true, false), // 18
122 new AudioFormat(22050.0F, 16, 2, true, true), // 19
123 /* 24 and 32 bit not yet possible
124 new AudioFormat(22050.0F, 24, 1, true, false),
125 new AudioFormat(22050.0F, 24, 1, true, true),
126 new AudioFormat(22050.0F, 24, 2, true, false),
127 new AudioFormat(22050.0F, 24, 2, true, true),
128 new AudioFormat(22050.0F, 32, 1, true, false),
129 new AudioFormat(22050.0F, 32, 1, true, true),
130 new AudioFormat(22050.0F, 32, 2, true, false),
131 new AudioFormat(22050.0F, 32, 2, true, true),
132 */
133 new AudioFormat(24000.0F, 16, 1, true, false), // 20
134 new AudioFormat(24000.0F, 16, 1, true, true), // 21
135 new AudioFormat(24000.0F, 16, 2, true, false), // 22
136 new AudioFormat(24000.0F, 16, 2, true, true), // 23
137 /* 24 and 32 bit not yet possible
138 new AudioFormat(24000.0F, 24, 1, true, false),
139 new AudioFormat(24000.0F, 24, 1, true, true),
140 new AudioFormat(24000.0F, 24, 2, true, false),
141 new AudioFormat(24000.0F, 24, 2, true, true),
142 new AudioFormat(24000.0F, 32, 1, true, false),
143 new AudioFormat(24000.0F, 32, 1, true, true),
144 new AudioFormat(24000.0F, 32, 2, true, false),
145 new AudioFormat(24000.0F, 32, 2, true, true),
146 */
147 new AudioFormat(32000.0F, 16, 1, true, false), // 24
148 new AudioFormat(32000.0F, 16, 1, true, true), // 25
149 new AudioFormat(32000.0F, 16, 2, true, false), // 26
150 new AudioFormat(32000.0F, 16, 2, true, true), // 27
151 /* 24 and 32 bit not yet possible
152 new AudioFormat(32000.0F, 24, 1, true, false),
153 new AudioFormat(32000.0F, 24, 1, true, true),
154 new AudioFormat(32000.0F, 24, 2, true, false),
155 new AudioFormat(32000.0F, 24, 2, true, true),
156 new AudioFormat(32000.0F, 32, 1, true, false),
157 new AudioFormat(32000.0F, 32, 1, true, true),
158 new AudioFormat(32000.0F, 32, 2, true, false),
159 new AudioFormat(32000.0F, 32, 2, true, true),
160 */
161 new AudioFormat(44100.0F, 16, 1, true, false), // 28
162 new AudioFormat(44100.0F, 16, 1, true, true), // 29
163 new AudioFormat(44100.0F, 16, 2, true, false), // 30
164 new AudioFormat(44100.0F, 16, 2, true, true), // 31
165 /* 24 and 32 bit not yet possible
166 new AudioFormat(44100.0F, 24, 1, true, false),
167 new AudioFormat(44100.0F, 24, 1, true, true),
168 new AudioFormat(44100.0F, 24, 2, true, false),
169 new AudioFormat(44100.0F, 24, 2, true, true),
170 new AudioFormat(44100.0F, 32, 1, true, false),
171 new AudioFormat(44100.0F, 32, 1, true, true),
172 new AudioFormat(44100.0F, 32, 2, true, false),
173 new AudioFormat(44100.0F, 32, 2, true, true),
174 */
175 new AudioFormat(48000.0F, 16, 1, true, false), // 32
176 new AudioFormat(48000.0F, 16, 1, true, true), // 33
177 new AudioFormat(48000.0F, 16, 2, true, false), // 34
178 new AudioFormat(48000.0F, 16, 2, true, true), // 35
179 /* 24 and 32 bit not yet possible
180 new AudioFormat(48000.0F, 24, 1, true, false),
181 new AudioFormat(48000.0F, 24, 1, true, true),
182 new AudioFormat(48000.0F, 24, 2, true, false),
183 new AudioFormat(48000.0F, 24, 2, true, true),
184 new AudioFormat(48000.0F, 32, 1, true, false),
185 new AudioFormat(48000.0F, 32, 1, true, true),
186 new AudioFormat(48000.0F, 32, 2, true, false),
187 new AudioFormat(48000.0F, 32, 2, true, true),
188 */
189 };
190
191 private static final boolean t = true;
192 private static final boolean f = false;
193
194 /*
195 * One row for each source format.
196 */
197 private static final boolean[][] CONVERSIONS =
198 {
199 {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
200 {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
201 {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
202 {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
203 {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
204 {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
205
206 {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
207 {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
208 {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
209 {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
210 {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
211 {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
212
213 {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
214 {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
215 {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
216 {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
217 {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
218 {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
219
220 };
221
222 /**
223 * Constructor.
224 */
225 public VorbisFormatConversionProvider()
226 {
227 super(Arrays.asList(INPUT_FORMATS), Arrays.asList(OUTPUT_FORMATS), CONVERSIONS);
228 }
229
230 /**
231 * Returns converted AudioInputStream.
232 */
233 public AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream audioInputStream)
234 {
235 if (isConversionSupported(targetFormat, audioInputStream.getFormat()))
236 {
237 return new DecodedVorbisAudioInputStream(targetFormat, audioInputStream);
238 }
239 else
240 {
241 throw new IllegalArgumentException("conversion not supported");
242 }
243 }
244}
diff --git a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileFormat.java b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileFormat.java
deleted file mode 100644
index 28b7c92a2a..0000000000
--- a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileFormat.java
+++ /dev/null
@@ -1,85 +0,0 @@
1/*
2 * VorbisAudioFileFormat.
3 *
4 * JavaZOOM : vorbisspi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23package javazoom.spi.vorbis.sampled.file;
24
25import java.util.Map;
26
27import javax.sound.sampled.AudioFormat;
28
29import org.tritonus.share.sampled.file.TAudioFileFormat;
30
31/**
32 * @author JavaZOOM
33 */
34public class VorbisAudioFileFormat extends TAudioFileFormat
35{
36 /**
37 * Contructor.
38 * @param type
39 * @param audioFormat
40 * @param nLengthInFrames
41 * @param nLengthInBytes
42 */
43 public VorbisAudioFileFormat(Type type, AudioFormat audioFormat, int nLengthInFrames, int nLengthInBytes, Map properties)
44 {
45 super(type, audioFormat, nLengthInFrames, nLengthInBytes, properties);
46 }
47
48 /**
49 * Ogg Vorbis audio file format parameters.
50 * Some parameters might be unavailable. So availability test is required before reading any parameter.
51 *
52 * <br>AudioFileFormat parameters.
53 * <ul>
54 * <li><b>duration</b> [Long], duration in microseconds.
55 * <li><b>title</b> [String], Title of the stream.
56 * <li><b>author</b> [String], Name of the artist of the stream.
57 * <li><b>album</b> [String], Name of the album of the stream.
58 * <li><b>date</b> [String], The date (year) of the recording or release of the stream.
59 * <li><b>copyright</b> [String], Copyright message of the stream.
60 * <li><b>comment</b> [String], Comment of the stream.
61 * </ul>
62 * <br>Ogg Vorbis parameters.
63 * <ul>
64 * <li><b>ogg.length.bytes</b> [Integer], length in bytes.
65 * <li><b>ogg.bitrate.min.bps</b> [Integer], minimum bitrate.
66 * <li><b>ogg.bitrate.nominal.bps</b> [Integer], nominal bitrate.
67 * <li><b>ogg.bitrate.max.bps</b> [Integer], maximum bitrate.
68 * <li><b>ogg.channels</b> [Integer], number of channels 1 : mono, 2 : stereo.
69 * <li><b>ogg.frequency.hz</b> [Integer], sampling rate in hz.
70 * <li><b>ogg.version</b> [Integer], version.
71 * <li><b>ogg.serial</b> [Integer], serial number.
72 * <li><b>ogg.comment.track</b> [String], track number.
73 * <li><b>ogg.comment.genre</b> [String], genre field.
74 * <li><b>ogg.comment.encodedby</b> [String], encoded by field.
75 * <li><b>ogg.comment.ext</b> [String], extended comments (indexed):
76 * <br>For instance :
77 * <br>ogg.comment.ext.1=Something
78 * <br>ogg.comment.ext.2=Another comment
79 * </ul>
80 */
81 public Map properties()
82 {
83 return super.properties();
84 }
85}
diff --git a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileReader.java b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileReader.java
deleted file mode 100644
index 40bc9cadee..0000000000
--- a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFileReader.java
+++ /dev/null
@@ -1,502 +0,0 @@
1/*
2 * VorbisAudioFileReader.
3 *
4 * JavaZOOM : vorbisspi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23package javazoom.spi.vorbis.sampled.file;
24
25import java.io.BufferedInputStream;
26import java.io.File;
27import java.io.FileInputStream;
28import java.io.IOException;
29import java.io.InputStream;
30import java.net.URL;
31import java.util.HashMap;
32import java.util.StringTokenizer;
33
34import javax.sound.sampled.AudioFileFormat;
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioInputStream;
37import javax.sound.sampled.AudioSystem;
38import javax.sound.sampled.UnsupportedAudioFileException;
39
40import org.tritonus.share.TDebug;
41import org.tritonus.share.sampled.file.TAudioFileReader;
42
43import com.jcraft.jogg.Packet;
44import com.jcraft.jogg.Page;
45import com.jcraft.jogg.StreamState;
46import com.jcraft.jogg.SyncState;
47import com.jcraft.jorbis.Block;
48import com.jcraft.jorbis.Comment;
49import com.jcraft.jorbis.DspState;
50import com.jcraft.jorbis.Info;
51import com.jcraft.jorbis.JOrbisException;
52import com.jcraft.jorbis.VorbisFile;
53
54/**
55 * This class implements the AudioFileReader class and provides an
56 * Ogg Vorbis file reader for use with the Java Sound Service Provider Interface.
57 */
58public class VorbisAudioFileReader extends TAudioFileReader
59{
60 private SyncState oggSyncState_ = null;
61 private StreamState oggStreamState_ = null;
62 private Page oggPage_ = null;
63 private Packet oggPacket_ = null;
64 private Info vorbisInfo = null;
65 private Comment vorbisComment = null;
66 private DspState vorbisDspState = null;
67 private Block vorbisBlock = null;
68 private int bufferMultiple_ = 4;
69 private int bufferSize_ = bufferMultiple_ * 256 * 2;
70 private int convsize = bufferSize_ * 2;
71 private byte[] convbuffer = new byte[convsize];
72 private byte[] buffer = null;
73 private int bytes = 0;
74 private int rate = 0;
75 private int channels = 0;
76
77 private int index = 0;
78 private InputStream oggBitStream_ = null;
79
80 private static final int INITAL_READ_LENGTH = 64000;
81 private static final int MARK_LIMIT = INITAL_READ_LENGTH + 1;
82
83 public VorbisAudioFileReader()
84 {
85 super(MARK_LIMIT, true);
86 }
87
88 /**
89 * Return the AudioFileFormat from the given file.
90 */
91 public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException
92 {
93 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioFileFormat(File file)");
94 InputStream inputStream = null;
95 try
96 {
97 inputStream = new BufferedInputStream(new FileInputStream(file));
98 inputStream.mark(MARK_LIMIT);
99 AudioFileFormat aff = getAudioFileFormat(inputStream);
100 inputStream.reset();
101 // Get Vorbis file info such as length in seconds.
102 VorbisFile vf = new VorbisFile(file.getAbsolutePath());
103 return getAudioFileFormat(inputStream,(int) file.length(), (int) Math.round((vf.time_total(-1))*1000));
104 }
105 catch (JOrbisException e)
106 {
107 throw new IOException(e.getMessage());
108 }
109 finally
110 {
111 if (inputStream != null) inputStream.close();
112 }
113 }
114
115 /**
116 * Return the AudioFileFormat from the given URL.
117 */
118 public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException
119 {
120 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioFileFormat(URL url)");
121 InputStream inputStream = url.openStream();
122 try
123 {
124 return getAudioFileFormat(inputStream);
125 }
126 finally
127 {
128 if (inputStream != null) inputStream.close();
129 }
130 }
131
132 /**
133 * Return the AudioFileFormat from the given InputStream.
134 */
135 public AudioFileFormat getAudioFileFormat(InputStream inputStream) throws UnsupportedAudioFileException, IOException
136 {
137 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioFileFormat(InputStream inputStream)");
138 try
139 {
140 if (!inputStream.markSupported()) inputStream = new BufferedInputStream(inputStream);
141 inputStream.mark(MARK_LIMIT);
142 return getAudioFileFormat(inputStream, AudioSystem.NOT_SPECIFIED, AudioSystem.NOT_SPECIFIED);
143 }
144 finally
145 {
146 inputStream.reset();
147 }
148 }
149
150 /**
151 * Return the AudioFileFormat from the given InputStream and length in bytes.
152 */
153 public AudioFileFormat getAudioFileFormat(InputStream inputStream, long medialength) throws UnsupportedAudioFileException, IOException
154 {
155 return getAudioFileFormat(inputStream, (int) medialength, AudioSystem.NOT_SPECIFIED);
156 }
157
158
159 /**
160 * Return the AudioFileFormat from the given InputStream, length in bytes and length in milliseconds.
161 */
162 protected AudioFileFormat getAudioFileFormat(InputStream bitStream, int mediaLength, int totalms) throws UnsupportedAudioFileException, IOException
163 {
164 HashMap aff_properties = new HashMap();
165 HashMap af_properties = new HashMap();
166 if (totalms == AudioSystem.NOT_SPECIFIED)
167 {
168 totalms = 0;
169 }
170 if (totalms <= 0)
171 {
172 totalms = 0;
173 }
174 else
175 {
176 aff_properties.put("duration",new Long(totalms*1000));
177 }
178 oggBitStream_ = bitStream;
179 init_jorbis();
180 index = 0;
181 try
182 {
183 readHeaders(aff_properties, af_properties);
184 }
185 catch (IOException ioe)
186 {
187 if (TDebug.TraceAudioFileReader)
188 {
189 TDebug.out(ioe.getMessage());
190 }
191 throw new UnsupportedAudioFileException(ioe.getMessage());
192 }
193
194 String dmp = vorbisInfo.toString();
195 if (TDebug.TraceAudioFileReader)
196 {
197 TDebug.out(dmp);
198 }
199 int ind = dmp.lastIndexOf("bitrate:");
200 int minbitrate = -1;
201 int nominalbitrate = -1;
202 int maxbitrate = -1;
203 if (ind != -1)
204 {
205 dmp = dmp.substring(ind + 8, dmp.length());
206 StringTokenizer st = new StringTokenizer(dmp, ",");
207 if (st.hasMoreTokens())
208 {
209 minbitrate = Integer.parseInt(st.nextToken());
210 }
211 if (st.hasMoreTokens())
212 {
213 nominalbitrate = Integer.parseInt(st.nextToken());
214 }
215 if (st.hasMoreTokens())
216 {
217 maxbitrate = Integer.parseInt(st.nextToken());
218 }
219 }
220 if (nominalbitrate > 0) af_properties.put("bitrate",new Integer(nominalbitrate));
221 af_properties.put("vbr",new Boolean(true));
222
223 if (minbitrate > 0) aff_properties.put("ogg.bitrate.min.bps",new Integer(minbitrate));
224 if (maxbitrate > 0) aff_properties.put("ogg.bitrate.max.bps",new Integer(maxbitrate));
225 if (nominalbitrate > 0) aff_properties.put("ogg.bitrate.nominal.bps",new Integer(nominalbitrate));
226 if (vorbisInfo.channels > 0) aff_properties.put("ogg.channels",new Integer(vorbisInfo.channels));
227 if (vorbisInfo.rate > 0) aff_properties.put("ogg.frequency.hz",new Integer(vorbisInfo.rate));
228 if (mediaLength > 0) aff_properties.put("ogg.length.bytes",new Integer(mediaLength));
229 aff_properties.put("ogg.version",new Integer(vorbisInfo.version));
230
231 AudioFormat.Encoding encoding = VorbisEncoding.VORBISENC;
232 AudioFormat format = new VorbisAudioFormat(encoding, vorbisInfo.rate, AudioSystem.NOT_SPECIFIED, vorbisInfo.channels, AudioSystem.NOT_SPECIFIED, AudioSystem.NOT_SPECIFIED, true,af_properties);
233 AudioFileFormat.Type type = VorbisFileFormatType.OGG;
234 return new VorbisAudioFileFormat(VorbisFileFormatType.OGG, format, AudioSystem.NOT_SPECIFIED, mediaLength,aff_properties);
235 }
236
237 /**
238 * Return the AudioInputStream from the given InputStream.
239 */
240 public AudioInputStream getAudioInputStream(InputStream inputStream) throws UnsupportedAudioFileException, IOException
241 {
242 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(InputStream inputStream)");
243 return getAudioInputStream(inputStream, AudioSystem.NOT_SPECIFIED, AudioSystem.NOT_SPECIFIED);
244 }
245
246 /**
247 * Return the AudioInputStream from the given InputStream.
248 */
249 public AudioInputStream getAudioInputStream(InputStream inputStream, int medialength, int totalms) throws UnsupportedAudioFileException, IOException
250 {
251 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(InputStream inputStreamint medialength, int totalms)");
252 try
253 {
254 if (!inputStream.markSupported()) inputStream = new BufferedInputStream(inputStream);
255 inputStream.mark(MARK_LIMIT);
256 AudioFileFormat audioFileFormat = getAudioFileFormat(inputStream, medialength, totalms);
257 inputStream.reset();
258 return new AudioInputStream(inputStream, audioFileFormat.getFormat(), audioFileFormat.getFrameLength());
259 }
260 catch (UnsupportedAudioFileException e)
261 {
262 inputStream.reset();
263 throw e;
264 }
265 catch (IOException e)
266 {
267 inputStream.reset();
268 throw e;
269 }
270 }
271
272 /**
273 * Return the AudioInputStream from the given File.
274 */
275 public AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException
276 {
277 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(File file)");
278 InputStream inputStream = new FileInputStream(file);
279 try
280 {
281 return getAudioInputStream(inputStream);
282 }
283 catch (UnsupportedAudioFileException e)
284 {
285 if (inputStream != null) inputStream.close();
286 throw e;
287 }
288 catch (IOException e)
289 {
290 if (inputStream != null) inputStream.close();
291 throw e;
292 }
293 }
294
295 /**
296 * Return the AudioInputStream from the given URL.
297 */
298 public AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException
299 {
300 if (TDebug.TraceAudioFileReader) TDebug.out("getAudioInputStream(URL url)");
301 InputStream inputStream = url.openStream();
302 try
303 {
304 return getAudioInputStream(inputStream);
305 }
306 catch (UnsupportedAudioFileException e)
307 {
308 if (inputStream != null) inputStream.close();
309 throw e;
310 }
311 catch (IOException e)
312 {
313 if (inputStream != null) inputStream.close();
314 throw e;
315 }
316 }
317
318 /**
319 * Reads headers and comments.
320 */
321 private void readHeaders(HashMap aff_properties, HashMap af_properties) throws IOException
322 {
323 if(TDebug.TraceAudioConverter) TDebug.out("readHeaders(");
324 index = oggSyncState_.buffer(bufferSize_);
325 buffer = oggSyncState_.data;
326 bytes = readFromStream(buffer, index, bufferSize_);
327 if(bytes == -1)
328 {
329 if(TDebug.TraceAudioConverter) TDebug.out("Cannot get any data from selected Ogg bitstream.");
330 throw new IOException("Cannot get any data from selected Ogg bitstream.");
331 }
332 oggSyncState_.wrote(bytes);
333 if(oggSyncState_.pageout(oggPage_) != 1)
334 {
335 if(bytes < bufferSize_)
336 {
337 throw new IOException("EOF");
338 }
339 if(TDebug.TraceAudioConverter) TDebug.out("Input does not appear to be an Ogg bitstream.");
340 throw new IOException("Input does not appear to be an Ogg bitstream.");
341 }
342 oggStreamState_.init(oggPage_.serialno());
343 vorbisInfo.init();
344 vorbisComment.init();
345 aff_properties.put("ogg.serial",new Integer(oggPage_.serialno()));
346 if(oggStreamState_.pagein(oggPage_) < 0)
347 {
348 // error; stream version mismatch perhaps
349 if(TDebug.TraceAudioConverter) TDebug.out("Error reading first page of Ogg bitstream data.");
350 throw new IOException("Error reading first page of Ogg bitstream data.");
351 }
352 if(oggStreamState_.packetout(oggPacket_) != 1)
353 {
354 // no page? must not be vorbis
355 if(TDebug.TraceAudioConverter) TDebug.out("Error reading initial header packet.");
356 throw new IOException("Error reading initial header packet.");
357 }
358 if(vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_) < 0)
359 {
360 // error case; not a vorbis header
361 if(TDebug.TraceAudioConverter) TDebug.out("This Ogg bitstream does not contain Vorbis audio data.");
362 throw new IOException("This Ogg bitstream does not contain Vorbis audio data.");
363 }
364 int i = 0;
365 while(i < 2)
366 {
367 while(i < 2)
368 {
369 int result = oggSyncState_.pageout(oggPage_);
370 if(result == 0)
371 {
372 break;
373 } // Need more data
374 if(result == 1)
375 {
376 oggStreamState_.pagein(oggPage_);
377 while(i < 2)
378 {
379 result = oggStreamState_.packetout(oggPacket_);
380 if(result == 0)
381 {
382 break;
383 }
384 if(result == -1)
385 {
386 if(TDebug.TraceAudioConverter) TDebug.out("Corrupt secondary header. Exiting.");
387 throw new IOException("Corrupt secondary header. Exiting.");
388 }
389 vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_);
390 i++;
391 }
392 }
393 }
394 index = oggSyncState_.buffer(bufferSize_);
395 buffer = oggSyncState_.data;
396 bytes = readFromStream(buffer, index, bufferSize_);
397 if(bytes == -1)
398 {
399 break;
400 }
401 if(bytes == 0 && i < 2)
402 {
403 if(TDebug.TraceAudioConverter) TDebug.out("End of file before finding all Vorbis headers!");
404 throw new IOException("End of file before finding all Vorbis headers!");
405 }
406 oggSyncState_.wrote(bytes);
407 }
408 // Read Ogg Vorbis comments.
409 byte[][] ptr = vorbisComment.user_comments;
410 String currComment = "";
411 int c = 0;
412 for(int j = 0; j < ptr.length; j++)
413 {
414 if(ptr[j] == null)
415 {
416 break;
417 }
418 currComment = (new String(ptr[j], 0, ptr[j].length - 1)).trim();
419 if(TDebug.TraceAudioConverter) TDebug.out(currComment);
420 if (currComment.toLowerCase().startsWith("artist"))
421 {
422 aff_properties.put("author",currComment.substring(7));
423 }
424 else if (currComment.toLowerCase().startsWith("title"))
425 {
426 aff_properties.put("title",currComment.substring(6));
427 }
428 else if (currComment.toLowerCase().startsWith("album"))
429 {
430 aff_properties.put("album",currComment.substring(6));
431 }
432 else if (currComment.toLowerCase().startsWith("date"))
433 {
434 aff_properties.put("date",currComment.substring(5));
435 }
436 else if (currComment.toLowerCase().startsWith("copyright"))
437 {
438 aff_properties.put("copyright",currComment.substring(10));
439 }
440 else if (currComment.toLowerCase().startsWith("comment"))
441 {
442 aff_properties.put("comment",currComment.substring(8));
443 }
444 else if (currComment.toLowerCase().startsWith("genre"))
445 {
446 aff_properties.put("ogg.comment.genre",currComment.substring(6));
447 }
448 else if (currComment.toLowerCase().startsWith("tracknumber"))
449 {
450 aff_properties.put("ogg.comment.track",currComment.substring(12));
451 }
452 else
453 {
454 c++;
455 aff_properties.put("ogg.comment.ext."+c,currComment);
456 }
457 aff_properties.put("ogg.comment.encodedby",new String(vorbisComment.vendor, 0, vorbisComment.vendor.length - 1));
458 }
459 }
460
461 /**
462 * Reads from the oggBitStream_ a specified number of Bytes(bufferSize_) worth
463 * starting at index and puts them in the specified buffer[].
464 *
465 * @return the number of bytes read or -1 if error.
466 */
467 private int readFromStream(byte[] buffer, int index, int bufferSize_)
468 {
469 int bytes = 0;
470 try
471 {
472 bytes = oggBitStream_.read(buffer, index, bufferSize_);
473 }
474 catch (Exception e)
475 {
476 if (TDebug.TraceAudioFileReader)
477 {
478 TDebug.out("Cannot Read Selected Song");
479 }
480 bytes = -1;
481 }
482 return bytes;
483 }
484
485 /**
486 * Initializes all the jOrbis and jOgg vars that are used for song playback.
487 */
488 private void init_jorbis()
489 {
490 oggSyncState_ = new SyncState();
491 oggStreamState_ = new StreamState();
492 oggPage_ = new Page();
493 oggPacket_ = new Packet();
494 vorbisInfo = new Info();
495 vorbisComment = new Comment();
496 vorbisDspState = new DspState();
497 vorbisBlock = new Block(vorbisDspState);
498 buffer = null;
499 bytes = 0;
500 oggSyncState_.init();
501 }
502}
diff --git a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFormat.java b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFormat.java
deleted file mode 100644
index 829ab2f8cd..0000000000
--- a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisAudioFormat.java
+++ /dev/null
@@ -1,66 +0,0 @@
1/*
2 * VorbisAudioFormat.
3 *
4 * JavaZOOM : vorbisspi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23package javazoom.spi.vorbis.sampled.file;
24
25import java.util.Map;
26
27import javax.sound.sampled.AudioFormat;
28
29import org.tritonus.share.sampled.TAudioFormat;
30
31/**
32 * @author JavaZOOM
33 */
34public class VorbisAudioFormat extends TAudioFormat
35{
36 /**
37 * Constructor.
38 * @param encoding
39 * @param nFrequency
40 * @param SampleSizeInBits
41 * @param nChannels
42 * @param FrameSize
43 * @param FrameRate
44 * @param isBigEndian
45 * @param properties
46 */
47 public VorbisAudioFormat(AudioFormat.Encoding encoding, float nFrequency, int SampleSizeInBits, int nChannels, int FrameSize, float FrameRate, boolean isBigEndian, Map properties)
48 {
49 super(encoding, nFrequency, SampleSizeInBits, nChannels, FrameSize, FrameRate, isBigEndian, properties);
50 }
51
52 /**
53 * Ogg Vorbis audio format parameters.
54 * Some parameters might be unavailable. So availability test is required before reading any parameter.
55 *
56 * <br>AudioFormat parameters.
57 * <ul>
58 * <li><b>bitrate</b> [Integer], bitrate in bits per seconds, average bitrate for VBR enabled stream.
59 * <li><b>vbr</b> [Boolean], VBR flag.
60 * </ul>
61 */
62 public Map properties()
63 {
64 return super.properties();
65 }
66}
diff --git a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisEncoding.java b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisEncoding.java
deleted file mode 100644
index 7800f1556d..0000000000
--- a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisEncoding.java
+++ /dev/null
@@ -1,41 +0,0 @@
1/*
2 * VorbisEncoding.
3 *
4 * JavaZOOM : vorbisspi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23package javazoom.spi.vorbis.sampled.file;
24
25import javax.sound.sampled.AudioFormat;
26
27/**
28 * Encodings used by the VORBIS audio decoder.
29 */
30public class VorbisEncoding extends AudioFormat.Encoding
31{
32 public static final AudioFormat.Encoding VORBISENC = new VorbisEncoding("VORBISENC");
33
34 /**
35 * Constructors.
36 */
37 public VorbisEncoding(String name)
38 {
39 super(name);
40 }
41}
diff --git a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisFileFormatType.java b/songdbj/javazoom/spi/vorbis/sampled/file/VorbisFileFormatType.java
deleted file mode 100644
index f006bbfe1d..0000000000
--- a/songdbj/javazoom/spi/vorbis/sampled/file/VorbisFileFormatType.java
+++ /dev/null
@@ -1,41 +0,0 @@
1/*
2 * VorbisFileFormatType.
3 *
4 * JavaZOOM : vorbisspi@javazoom.net
5 * http://www.javazoom.net
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23package javazoom.spi.vorbis.sampled.file;
24
25import javax.sound.sampled.AudioFileFormat;
26
27/**
28 * FileFormatTypes used by the VORBIS audio decoder.
29 */
30public class VorbisFileFormatType extends AudioFileFormat.Type
31{
32 public static final AudioFileFormat.Type VORBIS = new VorbisFileFormatType("VORBIS", "ogg");
33 public static final AudioFileFormat.Type OGG = new VorbisFileFormatType("OGG", "ogg");
34 /**
35 * Constructor.
36 */
37 public VorbisFileFormatType(String name, String extension)
38 {
39 super(name, extension);
40 }
41}