diff options
Diffstat (limited to 'songdbj/javazoom/spi/vorbis/sampled/convert')
-rw-r--r-- | songdbj/javazoom/spi/vorbis/sampled/convert/DecodedVorbisAudioInputStream.java | 519 | ||||
-rw-r--r-- | songdbj/javazoom/spi/vorbis/sampled/convert/VorbisFormatConversionProvider.java | 244 |
2 files changed, 763 insertions, 0 deletions
diff --git a/songdbj/javazoom/spi/vorbis/sampled/convert/DecodedVorbisAudioInputStream.java b/songdbj/javazoom/spi/vorbis/sampled/convert/DecodedVorbisAudioInputStream.java new file mode 100644 index 0000000000..b8e8577e13 --- /dev/null +++ b/songdbj/javazoom/spi/vorbis/sampled/convert/DecodedVorbisAudioInputStream.java | |||
@@ -0,0 +1,519 @@ | |||
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 | |||
24 | package javazoom.spi.vorbis.sampled.convert; | ||
25 | |||
26 | import java.io.IOException; | ||
27 | import java.io.InputStream; | ||
28 | import java.util.HashMap; | ||
29 | import java.util.Map; | ||
30 | |||
31 | import javax.sound.sampled.AudioFormat; | ||
32 | import javax.sound.sampled.AudioInputStream; | ||
33 | |||
34 | import javazoom.spi.PropertiesContainer; | ||
35 | |||
36 | import org.tritonus.share.TDebug; | ||
37 | import org.tritonus.share.sampled.convert.TAsynchronousFilteredAudioInputStream; | ||
38 | |||
39 | import com.jcraft.jogg.Packet; | ||
40 | import com.jcraft.jogg.Page; | ||
41 | import com.jcraft.jogg.StreamState; | ||
42 | import com.jcraft.jogg.SyncState; | ||
43 | import com.jcraft.jorbis.Block; | ||
44 | import com.jcraft.jorbis.Comment; | ||
45 | import com.jcraft.jorbis.DspState; | ||
46 | import com.jcraft.jorbis.Info; | ||
47 | |||
48 | /** | ||
49 | * This class implements the Vorbis decoding. | ||
50 | */ | ||
51 | public 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 new file mode 100644 index 0000000000..d1321f2590 --- /dev/null +++ b/songdbj/javazoom/spi/vorbis/sampled/convert/VorbisFormatConversionProvider.java | |||
@@ -0,0 +1,244 @@ | |||
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 | |||
23 | package javazoom.spi.vorbis.sampled.convert; | ||
24 | |||
25 | import java.util.Arrays; | ||
26 | import javazoom.spi.vorbis.sampled.file.VorbisEncoding; | ||
27 | import javax.sound.sampled.AudioFormat; | ||
28 | import javax.sound.sampled.AudioInputStream; | ||
29 | |||
30 | import org.tritonus.share.sampled.convert.TMatrixFormatConversionProvider; | ||
31 | |||
32 | /** | ||
33 | * ConversionProvider for VORBIS files. | ||
34 | */ | ||
35 | public 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 | } | ||