30 import java.util.ArrayList; |
30 import java.util.ArrayList; |
31 import java.util.Arrays; |
31 import java.util.Arrays; |
32 import java.util.Objects; |
32 import java.util.Objects; |
33 |
33 |
34 import javax.sound.sampled.AudioFormat; |
34 import javax.sound.sampled.AudioFormat; |
|
35 import javax.sound.sampled.AudioFormat.Encoding; |
35 import javax.sound.sampled.AudioInputStream; |
36 import javax.sound.sampled.AudioInputStream; |
36 import javax.sound.sampled.AudioSystem; |
37 import javax.sound.sampled.AudioSystem; |
37 import javax.sound.sampled.AudioFormat.Encoding; |
|
38 import javax.sound.sampled.spi.FormatConversionProvider; |
38 import javax.sound.sampled.spi.FormatConversionProvider; |
39 |
39 |
40 /** |
40 /** |
41 * This class is used to convert between 8,16,24,32 bit signed/unsigned |
41 * This class is used to convert between 8,16,24,32 bit signed/unsigned |
42 * big/litle endian fixed/floating stereo/mono/multi-channel audio streams and |
42 * big/litle endian fixed/floating stereo/mono/multi-channel audio streams and |
61 this.stream = stream; |
61 this.stream = stream; |
62 converter = AudioFloatConverter.getConverter(targetFormat); |
62 converter = AudioFloatConverter.getConverter(targetFormat); |
63 fsize = ((targetFormat.getSampleSizeInBits() + 7) / 8); |
63 fsize = ((targetFormat.getSampleSizeInBits() + 7) / 8); |
64 } |
64 } |
65 |
65 |
|
66 @Override |
66 public int read() throws IOException { |
67 public int read() throws IOException { |
67 byte[] b = new byte[1]; |
68 byte[] b = new byte[1]; |
68 int ret = read(b); |
69 int ret = read(b); |
69 if (ret < 0) |
70 if (ret < 0) |
70 return ret; |
71 return ret; |
71 return b[0] & 0xFF; |
72 return b[0] & 0xFF; |
72 } |
73 } |
73 |
74 |
|
75 @Override |
74 public int read(byte[] b, int off, int len) throws IOException { |
76 public int read(byte[] b, int off, int len) throws IOException { |
75 |
77 |
76 int flen = len / fsize; |
78 int flen = len / fsize; |
77 if (readfloatbuffer == null || readfloatbuffer.length < flen) |
79 if (readfloatbuffer == null || readfloatbuffer.length < flen) |
78 readfloatbuffer = new float[flen]; |
80 readfloatbuffer = new float[flen]; |
81 return ret; |
83 return ret; |
82 converter.toByteArray(readfloatbuffer, 0, ret, b, off); |
84 converter.toByteArray(readfloatbuffer, 0, ret, b, off); |
83 return ret * fsize; |
85 return ret * fsize; |
84 } |
86 } |
85 |
87 |
|
88 @Override |
86 public int available() throws IOException { |
89 public int available() throws IOException { |
87 int ret = stream.available(); |
90 int ret = stream.available(); |
88 if (ret < 0) |
91 if (ret < 0) |
89 return ret; |
92 return ret; |
90 return ret * fsize; |
93 return ret * fsize; |
91 } |
94 } |
92 |
95 |
|
96 @Override |
93 public void close() throws IOException { |
97 public void close() throws IOException { |
94 stream.close(); |
98 stream.close(); |
95 } |
99 } |
96 |
100 |
|
101 @Override |
97 public synchronized void mark(int readlimit) { |
102 public synchronized void mark(int readlimit) { |
98 stream.mark(readlimit * fsize); |
103 stream.mark(readlimit * fsize); |
99 } |
104 } |
100 |
105 |
|
106 @Override |
101 public boolean markSupported() { |
107 public boolean markSupported() { |
102 return stream.markSupported(); |
108 return stream.markSupported(); |
103 } |
109 } |
104 |
110 |
|
111 @Override |
105 public synchronized void reset() throws IOException { |
112 public synchronized void reset() throws IOException { |
106 stream.reset(); |
113 stream.reset(); |
107 } |
114 } |
108 |
115 |
|
116 @Override |
109 public long skip(long n) throws IOException { |
117 public long skip(long n) throws IOException { |
110 long ret = stream.skip(n / fsize); |
118 long ret = stream.skip(n / fsize); |
111 if (ret < 0) |
119 if (ret < 0) |
112 return ret; |
120 return ret; |
113 return ret * fsize; |
121 return ret * fsize; |
139 targetChannels, (format.getFrameSize() / sourceChannels) |
147 targetChannels, (format.getFrameSize() / sourceChannels) |
140 * targetChannels, format.getFrameRate(), format |
148 * targetChannels, format.getFrameRate(), format |
141 .isBigEndian()); |
149 .isBigEndian()); |
142 } |
150 } |
143 |
151 |
|
152 @Override |
144 public int available() throws IOException { |
153 public int available() throws IOException { |
145 return (ais.available() / sourceChannels) * targetChannels; |
154 return (ais.available() / sourceChannels) * targetChannels; |
146 } |
155 } |
147 |
156 |
|
157 @Override |
148 public void close() throws IOException { |
158 public void close() throws IOException { |
149 ais.close(); |
159 ais.close(); |
150 } |
160 } |
151 |
161 |
|
162 @Override |
152 public AudioFormat getFormat() { |
163 public AudioFormat getFormat() { |
153 return targetFormat; |
164 return targetFormat; |
154 } |
165 } |
155 |
166 |
|
167 @Override |
156 public long getFrameLength() { |
168 public long getFrameLength() { |
157 return ais.getFrameLength(); |
169 return ais.getFrameLength(); |
158 } |
170 } |
159 |
171 |
|
172 @Override |
160 public void mark(int readlimit) { |
173 public void mark(int readlimit) { |
161 ais.mark((readlimit / targetChannels) * sourceChannels); |
174 ais.mark((readlimit / targetChannels) * sourceChannels); |
162 } |
175 } |
163 |
176 |
|
177 @Override |
164 public boolean markSupported() { |
178 public boolean markSupported() { |
165 return ais.markSupported(); |
179 return ais.markSupported(); |
166 } |
180 } |
167 |
181 |
|
182 @Override |
168 public int read(float[] b, int off, int len) throws IOException { |
183 public int read(float[] b, int off, int len) throws IOException { |
169 int len2 = (len / targetChannels) * sourceChannels; |
184 int len2 = (len / targetChannels) * sourceChannels; |
170 if (conversion_buffer == null || conversion_buffer.length < len2) |
185 if (conversion_buffer == null || conversion_buffer.length < len2) |
171 conversion_buffer = new float[len2]; |
186 conversion_buffer = new float[len2]; |
172 int ret = ais.read(conversion_buffer, 0, len2); |
187 int ret = ais.read(conversion_buffer, 0, len2); |
303 ibuffer2 = new float[nrofchannels * buffer_len]; |
320 ibuffer2 = new float[nrofchannels * buffer_len]; |
304 ibuffer_index = buffer_len + pad; |
321 ibuffer_index = buffer_len + pad; |
305 ibuffer_len = buffer_len; |
322 ibuffer_len = buffer_len; |
306 } |
323 } |
307 |
324 |
|
325 @Override |
308 public int available() throws IOException { |
326 public int available() throws IOException { |
309 return 0; |
327 return 0; |
310 } |
328 } |
311 |
329 |
|
330 @Override |
312 public void close() throws IOException { |
331 public void close() throws IOException { |
313 ais.close(); |
332 ais.close(); |
314 } |
333 } |
315 |
334 |
|
335 @Override |
316 public AudioFormat getFormat() { |
336 public AudioFormat getFormat() { |
317 return targetFormat; |
337 return targetFormat; |
318 } |
338 } |
319 |
339 |
|
340 @Override |
320 public long getFrameLength() { |
341 public long getFrameLength() { |
321 return AudioSystem.NOT_SPECIFIED; // ais.getFrameLength(); |
342 return AudioSystem.NOT_SPECIFIED; // ais.getFrameLength(); |
322 } |
343 } |
323 |
344 |
|
345 @Override |
324 public void mark(int readlimit) { |
346 public void mark(int readlimit) { |
325 ais.mark((int) (readlimit * pitch[0])); |
347 ais.mark((int) (readlimit * pitch[0])); |
326 mark_ibuffer_index = ibuffer_index; |
348 mark_ibuffer_index = ibuffer_index; |
327 mark_ibuffer_len = ibuffer_len; |
349 mark_ibuffer_len = ibuffer_len; |
328 if (mark_ibuffer == null) { |
350 if (mark_ibuffer == null) { |
472 |
498 |
473 private final Encoding[] formats = {Encoding.PCM_SIGNED, |
499 private final Encoding[] formats = {Encoding.PCM_SIGNED, |
474 Encoding.PCM_UNSIGNED, |
500 Encoding.PCM_UNSIGNED, |
475 Encoding.PCM_FLOAT}; |
501 Encoding.PCM_FLOAT}; |
476 |
502 |
|
503 @Override |
477 public AudioInputStream getAudioInputStream(Encoding targetEncoding, |
504 public AudioInputStream getAudioInputStream(Encoding targetEncoding, |
478 AudioInputStream sourceStream) { |
505 AudioInputStream sourceStream) { |
479 if (!isConversionSupported(targetEncoding, sourceStream.getFormat())) { |
506 if (!isConversionSupported(targetEncoding, sourceStream.getFormat())) { |
480 throw new IllegalArgumentException( |
507 throw new IllegalArgumentException( |
481 "Unsupported conversion: " + sourceStream.getFormat() |
508 "Unsupported conversion: " + sourceStream.getFormat() |
482 .toString() + " to " + targetEncoding.toString()); |
509 .toString() + " to " + targetEncoding.toString()); |
483 } |
510 } |
494 AudioFormat targetFormat = new AudioFormat(encoding, samplerate, bits, |
521 AudioFormat targetFormat = new AudioFormat(encoding, samplerate, bits, |
495 channels, channels * bits / 8, samplerate, bigendian); |
522 channels, channels * bits / 8, samplerate, bigendian); |
496 return getAudioInputStream(targetFormat, sourceStream); |
523 return getAudioInputStream(targetFormat, sourceStream); |
497 } |
524 } |
498 |
525 |
|
526 @Override |
499 public AudioInputStream getAudioInputStream(AudioFormat targetFormat, |
527 public AudioInputStream getAudioInputStream(AudioFormat targetFormat, |
500 AudioInputStream sourceStream) { |
528 AudioInputStream sourceStream) { |
501 if (!isConversionSupported(targetFormat, sourceStream.getFormat())) |
529 if (!isConversionSupported(targetFormat, sourceStream.getFormat())) |
502 throw new IllegalArgumentException("Unsupported conversion: " |
530 throw new IllegalArgumentException("Unsupported conversion: " |
503 + sourceStream.getFormat().toString() + " to " |
531 + sourceStream.getFormat().toString() + " to " |
504 + targetFormat.toString()); |
532 + targetFormat.toString()); |
505 return getAudioInputStream(targetFormat, AudioFloatInputStream |
533 return getAudioInputStream(targetFormat, AudioFloatInputStream |
524 return new AudioInputStream(new AudioFloatFormatConverterInputStream( |
552 return new AudioInputStream(new AudioFloatFormatConverterInputStream( |
525 targetFormat, sourceStream), targetFormat, sourceStream |
553 targetFormat, sourceStream), targetFormat, sourceStream |
526 .getFrameLength()); |
554 .getFrameLength()); |
527 } |
555 } |
528 |
556 |
|
557 @Override |
529 public Encoding[] getSourceEncodings() { |
558 public Encoding[] getSourceEncodings() { |
530 return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED, |
559 return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED, |
531 Encoding.PCM_FLOAT }; |
560 Encoding.PCM_FLOAT }; |
532 } |
561 } |
533 |
562 |
|
563 @Override |
534 public Encoding[] getTargetEncodings() { |
564 public Encoding[] getTargetEncodings() { |
535 return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED, |
565 return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED, |
536 Encoding.PCM_FLOAT }; |
566 Encoding.PCM_FLOAT }; |
537 } |
567 } |
538 |
568 |
|
569 @Override |
539 public Encoding[] getTargetEncodings(AudioFormat sourceFormat) { |
570 public Encoding[] getTargetEncodings(AudioFormat sourceFormat) { |
540 if (AudioFloatConverter.getConverter(sourceFormat) == null) |
571 if (AudioFloatConverter.getConverter(sourceFormat) == null) |
541 return new Encoding[0]; |
572 return new Encoding[0]; |
542 return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED, |
573 return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED, |
543 Encoding.PCM_FLOAT }; |
574 Encoding.PCM_FLOAT }; |
544 } |
575 } |
545 |
576 |
|
577 @Override |
546 public AudioFormat[] getTargetFormats(Encoding targetEncoding, |
578 public AudioFormat[] getTargetFormats(Encoding targetEncoding, |
547 AudioFormat sourceFormat) { |
579 AudioFormat sourceFormat) { |
548 Objects.requireNonNull(targetEncoding); |
580 Objects.requireNonNull(targetEncoding); |
549 if (AudioFloatConverter.getConverter(sourceFormat) == null) |
581 if (AudioFloatConverter.getConverter(sourceFormat) == null) |
550 return new AudioFormat[0]; |
582 return new AudioFormat[0]; |
551 int channels = sourceFormat.getChannels(); |
583 int channels = sourceFormat.getChannels(); |
552 |
584 |
553 ArrayList<AudioFormat> formats = new ArrayList<AudioFormat>(); |
585 ArrayList<AudioFormat> formats = new ArrayList<>(); |
554 |
586 |
555 if (targetEncoding.equals(Encoding.PCM_SIGNED)) |
587 if (targetEncoding.equals(Encoding.PCM_SIGNED)) |
556 formats.add(new AudioFormat(Encoding.PCM_SIGNED, |
588 formats.add(new AudioFormat(Encoding.PCM_SIGNED, |
557 AudioSystem.NOT_SPECIFIED, 8, channels, channels, |
589 AudioSystem.NOT_SPECIFIED, 8, channels, channels, |
558 AudioSystem.NOT_SPECIFIED, false)); |
590 AudioSystem.NOT_SPECIFIED, false)); |
596 } |
628 } |
597 |
629 |
598 return formats.toArray(new AudioFormat[formats.size()]); |
630 return formats.toArray(new AudioFormat[formats.size()]); |
599 } |
631 } |
600 |
632 |
|
633 @Override |
601 public boolean isConversionSupported(AudioFormat targetFormat, |
634 public boolean isConversionSupported(AudioFormat targetFormat, |
602 AudioFormat sourceFormat) { |
635 AudioFormat sourceFormat) { |
603 Objects.requireNonNull(targetFormat); |
636 Objects.requireNonNull(targetFormat); |
604 if (AudioFloatConverter.getConverter(sourceFormat) == null) |
637 if (AudioFloatConverter.getConverter(sourceFormat) == null) |
605 return false; |
638 return false; |
606 if (AudioFloatConverter.getConverter(targetFormat) == null) |
639 if (AudioFloatConverter.getConverter(targetFormat) == null) |
607 return false; |
640 return false; |
610 if (targetFormat.getChannels() <= 0) |
643 if (targetFormat.getChannels() <= 0) |
611 return false; |
644 return false; |
612 return true; |
645 return true; |
613 } |
646 } |
614 |
647 |
|
648 @Override |
615 public boolean isConversionSupported(Encoding targetEncoding, |
649 public boolean isConversionSupported(Encoding targetEncoding, |
616 AudioFormat sourceFormat) { |
650 AudioFormat sourceFormat) { |
617 Objects.requireNonNull(targetEncoding); |
651 Objects.requireNonNull(targetEncoding); |
618 if (AudioFloatConverter.getConverter(sourceFormat) == null) |
652 if (AudioFloatConverter.getConverter(sourceFormat) == null) |
619 return false; |
653 return false; |
620 for (int i = 0; i < formats.length; i++) { |
654 for (int i = 0; i < formats.length; i++) { |
621 if (targetEncoding.equals(formats[i])) |
655 if (targetEncoding.equals(formats[i])) |