Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java
41161 views
1
/*
2
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package com.sun.media.sound;
27
28
import java.io.IOException;
29
import java.util.Objects;
30
import java.util.Vector;
31
32
import javax.sound.sampled.AudioFormat;
33
import javax.sound.sampled.AudioFormat.Encoding;
34
import javax.sound.sampled.AudioInputStream;
35
import javax.sound.sampled.AudioSystem;
36
import javax.sound.sampled.spi.FormatConversionProvider;
37
38
/**
39
* A-law encodes linear data, and decodes a-law data to linear data.
40
*
41
* @author Kara Kytle
42
*/
43
public final class AlawCodec extends FormatConversionProvider {
44
45
/* Tables used for A-law decoding */
46
47
private static final byte[] ALAW_TABH = new byte[256];
48
private static final byte[] ALAW_TABL = new byte[256];
49
50
private static final short[] seg_end = {
51
0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
52
};
53
54
/**
55
* Initializes the decode tables.
56
*/
57
static {
58
for (int i=0;i<256;i++) {
59
int input = i ^ 0x55;
60
int mantissa = (input & 0xf ) << 4;
61
int segment = (input & 0x70) >> 4;
62
int value = mantissa+8;
63
64
if(segment>=1)
65
value+=0x100;
66
if(segment>1)
67
value <<= (segment -1);
68
69
if( (input & 0x80)==0 )
70
value = -value;
71
72
ALAW_TABL[i] = (byte)value;
73
ALAW_TABH[i] = (byte)(value>>8);
74
}
75
}
76
77
@Override
78
public AudioFormat.Encoding[] getSourceEncodings() {
79
return new Encoding[]{Encoding.ALAW, Encoding.PCM_SIGNED};
80
}
81
82
@Override
83
public AudioFormat.Encoding[] getTargetEncodings() {
84
return getSourceEncodings();
85
}
86
87
@Override
88
public AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat){
89
90
if( sourceFormat.getEncoding().equals( AudioFormat.Encoding.PCM_SIGNED )) {
91
92
if( sourceFormat.getSampleSizeInBits() == 16 ) {
93
94
AudioFormat.Encoding[] enc = new AudioFormat.Encoding[1];
95
enc[0] = AudioFormat.Encoding.ALAW;
96
return enc;
97
98
} else {
99
return new AudioFormat.Encoding[0];
100
}
101
} else if( sourceFormat.getEncoding().equals( AudioFormat.Encoding.ALAW ) ) {
102
103
if( sourceFormat.getSampleSizeInBits() == 8 ) {
104
105
AudioFormat.Encoding[] enc = new AudioFormat.Encoding[1];
106
enc[0] = AudioFormat.Encoding.PCM_SIGNED;
107
return enc;
108
109
} else {
110
return new AudioFormat.Encoding[0];
111
}
112
113
} else {
114
return new AudioFormat.Encoding[0];
115
}
116
}
117
118
@Override
119
public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat){
120
Objects.requireNonNull(sourceFormat);
121
if( (targetEncoding.equals( AudioFormat.Encoding.PCM_SIGNED ) && sourceFormat.getEncoding().equals( AudioFormat.Encoding.ALAW)) ||
122
(targetEncoding.equals( AudioFormat.Encoding.ALAW) && sourceFormat.getEncoding().equals( AudioFormat.Encoding.PCM_SIGNED)) ) {
123
return getOutputFormats( sourceFormat );
124
} else {
125
return new AudioFormat[0];
126
}
127
}
128
129
@Override
130
public AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding, AudioInputStream sourceStream){
131
AudioFormat sourceFormat = sourceStream.getFormat();
132
AudioFormat.Encoding sourceEncoding = sourceFormat.getEncoding();
133
134
if( !isConversionSupported(targetEncoding,sourceStream.getFormat()) ) {
135
throw new IllegalArgumentException("Unsupported conversion: " + sourceStream.getFormat().toString() + " to " + targetEncoding.toString());
136
}
137
if( sourceEncoding.equals( targetEncoding ) ) {
138
return sourceStream;
139
}
140
AudioFormat targetFormat = null;
141
if( sourceEncoding.equals( AudioFormat.Encoding.ALAW ) &&
142
targetEncoding.equals( AudioFormat.Encoding.PCM_SIGNED ) ) {
143
144
targetFormat = new AudioFormat( targetEncoding,
145
sourceFormat.getSampleRate(),
146
16,
147
sourceFormat.getChannels(),
148
2*sourceFormat.getChannels(),
149
sourceFormat.getSampleRate(),
150
sourceFormat.isBigEndian());
151
152
} else if( sourceEncoding.equals( AudioFormat.Encoding.PCM_SIGNED ) &&
153
targetEncoding.equals( AudioFormat.Encoding.ALAW ) ) {
154
155
targetFormat = new AudioFormat( targetEncoding,
156
sourceFormat.getSampleRate(),
157
8,
158
sourceFormat.getChannels(),
159
sourceFormat.getChannels(),
160
sourceFormat.getSampleRate(),
161
false);
162
} else {
163
throw new IllegalArgumentException("Unsupported conversion: " + sourceStream.getFormat().toString() + " to " + targetEncoding.toString());
164
}
165
return getConvertedStream(targetFormat, sourceStream);
166
}
167
168
@Override
169
public AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream sourceStream){
170
if (!isConversionSupported(targetFormat, sourceStream.getFormat()))
171
throw new IllegalArgumentException("Unsupported conversion: "
172
+ sourceStream.getFormat().toString() + " to "
173
+ targetFormat.toString());
174
return getConvertedStream( targetFormat, sourceStream );
175
}
176
177
/**
178
* Opens the codec with the specified parameters.
179
* @param stream stream from which data to be processed should be read
180
* @param outputFormat desired data format of the stream after processing
181
* @return stream from which processed data may be read
182
* @throws IllegalArgumentException if the format combination supplied is
183
* not supported.
184
*/
185
private AudioInputStream getConvertedStream(AudioFormat outputFormat, AudioInputStream stream) {
186
187
AudioInputStream cs = null;
188
AudioFormat inputFormat = stream.getFormat();
189
190
if( inputFormat.matches(outputFormat) ) {
191
cs = stream;
192
} else {
193
cs = new AlawCodecStream(stream, outputFormat);
194
}
195
196
return cs;
197
}
198
199
/**
200
* Obtains the set of output formats supported by the codec
201
* given a particular input format.
202
* If no output formats are supported for this input format,
203
* returns an array of length 0.
204
* @return array of supported output formats.
205
*/
206
private AudioFormat[] getOutputFormats(AudioFormat inputFormat) {
207
208
209
Vector<AudioFormat> formats = new Vector<>();
210
AudioFormat format;
211
212
if (inputFormat.getSampleSizeInBits() == 16
213
&& AudioFormat.Encoding.PCM_SIGNED.equals(inputFormat.getEncoding())) {
214
format = new AudioFormat(AudioFormat.Encoding.ALAW,
215
inputFormat.getSampleRate(), 8,
216
inputFormat.getChannels(),
217
inputFormat.getChannels(),
218
inputFormat.getSampleRate(), false);
219
formats.addElement(format);
220
}
221
if (inputFormat.getSampleSizeInBits() == 8
222
&& AudioFormat.Encoding.ALAW.equals(inputFormat.getEncoding())) {
223
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
224
inputFormat.getSampleRate(), 16,
225
inputFormat.getChannels(),
226
inputFormat.getChannels() * 2,
227
inputFormat.getSampleRate(), false);
228
formats.addElement(format);
229
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
230
inputFormat.getSampleRate(), 16,
231
inputFormat.getChannels(),
232
inputFormat.getChannels() * 2,
233
inputFormat.getSampleRate(), true);
234
formats.addElement(format);
235
}
236
237
AudioFormat[] formatArray = new AudioFormat[formats.size()];
238
for (int i = 0; i < formatArray.length; i++) {
239
formatArray[i] = formats.elementAt(i);
240
}
241
return formatArray;
242
}
243
244
245
private final class AlawCodecStream extends AudioInputStream {
246
247
// tempBuffer required only for encoding (when encode is true)
248
private static final int tempBufferSize = 64;
249
private byte[] tempBuffer = null;
250
251
/**
252
* True to encode to a-law, false to decode to linear
253
*/
254
boolean encode = false;
255
256
AudioFormat encodeFormat;
257
AudioFormat decodeFormat;
258
259
byte[] tabByte1 = null;
260
byte[] tabByte2 = null;
261
int highByte = 0;
262
int lowByte = 1;
263
264
AlawCodecStream(AudioInputStream stream, AudioFormat outputFormat) {
265
266
super(stream, outputFormat, -1);
267
268
AudioFormat inputFormat = stream.getFormat();
269
270
// throw an IllegalArgumentException if not ok
271
if ( ! (isConversionSupported(outputFormat, inputFormat)) ) {
272
273
throw new IllegalArgumentException("Unsupported conversion: " + inputFormat.toString() + " to " + outputFormat.toString());
274
}
275
276
//$$fb 2002-07-18: fix for 4714846: JavaSound ULAW (8-bit) encoder erroneously depends on endian-ness
277
boolean PCMIsBigEndian;
278
279
// determine whether we are encoding or decoding
280
if (AudioFormat.Encoding.ALAW.equals(inputFormat.getEncoding())) {
281
encode = false;
282
encodeFormat = inputFormat;
283
decodeFormat = outputFormat;
284
PCMIsBigEndian = outputFormat.isBigEndian();
285
} else {
286
encode = true;
287
encodeFormat = outputFormat;
288
decodeFormat = inputFormat;
289
PCMIsBigEndian = inputFormat.isBigEndian();
290
tempBuffer = new byte[tempBufferSize];
291
}
292
293
if (PCMIsBigEndian) {
294
tabByte1 = ALAW_TABH;
295
tabByte2 = ALAW_TABL;
296
highByte = 0;
297
lowByte = 1;
298
} else {
299
tabByte1 = ALAW_TABL;
300
tabByte2 = ALAW_TABH;
301
highByte = 1;
302
lowByte = 0;
303
}
304
305
// set the AudioInputStream length in frames if we know it
306
if (stream instanceof AudioInputStream) {
307
frameLength = stream.getFrameLength();
308
}
309
310
// set framePos to zero
311
framePos = 0;
312
frameSize = inputFormat.getFrameSize();
313
if( frameSize==AudioSystem.NOT_SPECIFIED ) {
314
frameSize=1;
315
}
316
}
317
318
319
/*
320
* $$jb 2/23/99
321
* Used to determine segment number in aLaw encoding
322
*/
323
private short search(short val, short[] table, short size) {
324
for(short i = 0; i < size; i++) {
325
if (val <= table[i]) { return i; }
326
}
327
return size;
328
}
329
330
/**
331
* Note that this won't actually read anything; must read in
332
* two-byte units.
333
*/
334
@Override
335
public int read() throws IOException {
336
337
byte[] b = new byte[1];
338
return read(b, 0, b.length);
339
}
340
341
@Override
342
public int read(byte[] b) throws IOException {
343
344
return read(b, 0, b.length);
345
}
346
347
@Override
348
public int read(byte[] b, int off, int len) throws IOException {
349
350
// don't read fractional frames
351
if( len%frameSize != 0 ) {
352
len -= (len%frameSize);
353
}
354
355
if (encode) {
356
357
short QUANT_MASK = 0xF;
358
short SEG_SHIFT = 4;
359
short mask;
360
short seg;
361
int adj;
362
int i;
363
364
short sample;
365
byte enc;
366
367
int readCount = 0;
368
int currentPos = off;
369
int readLeft = len*2;
370
int readLen = ( (readLeft>tempBufferSize) ? tempBufferSize : readLeft );
371
372
while ((readCount = super.read(tempBuffer,0,readLen))>0) {
373
374
for (i = 0; i < readCount; i+=2) {
375
376
/* Get the sample from the tempBuffer */
377
sample = (short)(( (tempBuffer[i + highByte]) << 8) & 0xFF00);
378
sample |= (short)( (tempBuffer[i + lowByte]) & 0xFF);
379
380
if(sample >= 0) {
381
mask = 0xD5;
382
} else {
383
mask = 0x55;
384
sample = (short)(-sample - 8);
385
}
386
/* Convert the scaled magnitude to segment number. */
387
seg = search(sample, seg_end, (short) 8);
388
/*
389
* Combine the sign, segment, quantization bits
390
*/
391
if (seg >= 8) { /* out of range, return maximum value. */
392
enc = (byte) (0x7F ^ mask);
393
} else {
394
enc = (byte) (seg << SEG_SHIFT);
395
if(seg < 2) {
396
enc |= (byte) ( (sample >> 4) & QUANT_MASK);
397
} else {
398
enc |= (byte) ( (sample >> (seg + 3)) & QUANT_MASK );
399
}
400
enc ^= mask;
401
}
402
/* Now put the encoded sample where it belongs */
403
b[currentPos] = enc;
404
currentPos++;
405
}
406
/* And update pointers and counters for next iteration */
407
readLeft -= readCount;
408
readLen = ( (readLeft>tempBufferSize) ? tempBufferSize : readLeft );
409
}
410
411
if( currentPos==off && readCount<0 ) { // EOF or error
412
return readCount;
413
}
414
415
return (currentPos - off); /* Number of bytes written to new buffer */
416
417
} else {
418
419
int i;
420
int readLen = len/2;
421
int readOffset = off + len/2;
422
int readCount = super.read(b, readOffset, readLen);
423
424
for (i = off; i < (off + (readCount*2)); i+=2) {
425
b[i] = tabByte1[b[readOffset] & 0xFF];
426
b[i+1] = tabByte2[b[readOffset] & 0xFF];
427
readOffset++;
428
}
429
430
if( readCount<0 ) { // EOF or error
431
return readCount;
432
}
433
434
return (i - off);
435
}
436
}
437
438
@Override
439
public long skip(final long n) throws IOException {
440
// Implementation of this method assumes that we support
441
// encoding/decoding from/to 8/16 bits only
442
return encode ? super.skip(n * 2) / 2 : super.skip(n / 2) * 2;
443
}
444
} // end class AlawCodecStream
445
} // end class ALAW
446
447