summaryrefslogtreecommitdiff
path: root/songdbj/org/tritonus/share/sampled/FloatSampleTools.java
diff options
context:
space:
mode:
Diffstat (limited to 'songdbj/org/tritonus/share/sampled/FloatSampleTools.java')
-rw-r--r--songdbj/org/tritonus/share/sampled/FloatSampleTools.java696
1 files changed, 696 insertions, 0 deletions
diff --git a/songdbj/org/tritonus/share/sampled/FloatSampleTools.java b/songdbj/org/tritonus/share/sampled/FloatSampleTools.java
new file mode 100644
index 0000000000..76913ba39e
--- /dev/null
+++ b/songdbj/org/tritonus/share/sampled/FloatSampleTools.java
@@ -0,0 +1,696 @@
1/*
2 * FloatSampleTools.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000,2004 by Florian Bomers <http://www.bomers.de>
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/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled;
30
31import java.util.*;
32import javax.sound.sampled.*;
33import org.tritonus.share.TDebug;
34
35/**
36 * Utility functions for handling data in normalized float arrays.
37 * Each sample is linear in the range of [-1.0f, +1.0f].
38 * <p>
39 * Currently, the following bit sizes are supported:
40 * <ul>
41 * <li>8-bit
42 * <li>16-bit
43 * <li>packed 24-bit (stored in 3 bytes)
44 * <li>32-bit
45 * </ul>
46 * 8-bit data can be unsigned or signed. All other data is only
47 * supported in signed encoding.
48 *
49 * @see FloatSampleBuffer
50 * @author Florian Bomers
51 */
52
53public class FloatSampleTools {
54
55 /** default number of bits to be dithered: 0.7f */
56 public static final float DEFAULT_DITHER_BITS = 0.7f;
57
58 private static Random random = null;
59
60 // sample width (must be in order !)
61 static final int F_8=1;
62 static final int F_16=2;
63 static final int F_24=3;
64 static final int F_32=4;
65 static final int F_SAMPLE_WIDTH_MASK=F_8 | F_16 | F_24 | F_32;
66
67 // format bit-flags
68 static final int F_SIGNED=8;
69 static final int F_BIGENDIAN=16;
70
71 // supported formats
72 static final int CT_8S=F_8 | F_SIGNED;
73 static final int CT_8U=F_8;
74 static final int CT_16SB=F_16 | F_SIGNED | F_BIGENDIAN;
75 static final int CT_16SL=F_16 | F_SIGNED;
76 static final int CT_24SB=F_24 | F_SIGNED | F_BIGENDIAN;
77 static final int CT_24SL=F_24 | F_SIGNED;
78 static final int CT_32SB=F_32 | F_SIGNED | F_BIGENDIAN;
79 static final int CT_32SL=F_32 | F_SIGNED;
80
81 // ////////////////////////////// initialization /////////////////////////////// //
82
83 /** prevent instanciation */
84 private FloatSampleTools() {
85 }
86
87
88 // /////////////////// FORMAT / FORMAT TYPE /////////////////////////////////// //
89
90 /**
91 * only allow "packed" samples -- currently no support for 18, 20, 24_32 bits.
92 * @throws IllegalArgumentException
93 */
94 static void checkSupportedSampleSize(int ssib, int channels, int frameSize) {
95 if ((ssib*channels) != frameSize * 8) {
96 throw new IllegalArgumentException("unsupported sample size: "+ssib
97 +" stored in "+(frameSize/channels)+" bytes.");
98 }
99 }
100
101
102 /**
103 * Get the formatType code from the given format.
104 * @throws IllegalArgumentException
105 */
106 static int getFormatType(AudioFormat format) {
107 boolean signed = format.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED);
108 if (!signed &&
109 !format.getEncoding().equals(AudioFormat.Encoding.PCM_UNSIGNED)) {
110 throw new IllegalArgumentException
111 ("unsupported encoding: only PCM encoding supported.");
112 }
113 if (!signed && format.getSampleSizeInBits() != 8) {
114 throw new IllegalArgumentException
115 ("unsupported encoding: only 8-bit can be unsigned");
116 }
117 checkSupportedSampleSize(format.getSampleSizeInBits(),
118 format.getChannels(),
119 format.getFrameSize());
120
121 int formatType = getFormatType(format.getSampleSizeInBits(),
122 signed, format.isBigEndian());
123 return formatType;
124 }
125
126 /**
127 * @throws IllegalArgumentException
128 */
129 static int getFormatType(int ssib, boolean signed, boolean bigEndian) {
130 int bytesPerSample=ssib/8;
131 int res=0;
132 if (ssib==8) {
133 res=F_8;
134 } else if (ssib==16) {
135 res=F_16;
136 } else if (ssib==24) {
137 res=F_24;
138 } else if (ssib==32) {
139 res=F_32;
140 }
141 if (res==0) {
142 throw new IllegalArgumentException
143 ("FloatSampleBuffer: unsupported sample size of "
144 +ssib+" bits per sample.");
145 }
146 if (!signed && bytesPerSample>1) {
147 throw new IllegalArgumentException
148 ("FloatSampleBuffer: unsigned samples larger than "
149 +"8 bit are not supported");
150 }
151 if (signed) {
152 res|=F_SIGNED;
153 }
154 if (bigEndian && (ssib!=8)) {
155 res|=F_BIGENDIAN;
156 }
157 return res;
158 }
159
160 static int getSampleSize(int formatType) {
161 switch (formatType & F_SAMPLE_WIDTH_MASK) {
162 case F_8: return 1;
163 case F_16: return 2;
164 case F_24: return 3;
165 case F_32: return 4;
166 }
167 return 0;
168 }
169
170 /**
171 * Return a string representation of this format
172 */
173 static String formatType2Str(int formatType) {
174 String res=""+formatType+": ";
175 switch (formatType & F_SAMPLE_WIDTH_MASK) {
176 case F_8:
177 res+="8bit";
178 break;
179 case F_16:
180 res+="16bit";
181 break;
182 case F_24:
183 res+="24bit";
184 break;
185 case F_32:
186 res+="32bit";
187 break;
188 }
189 res+=((formatType & F_SIGNED)==F_SIGNED)?" signed":" unsigned";
190 if ((formatType & F_SAMPLE_WIDTH_MASK)!=F_8) {
191 res+=((formatType & F_BIGENDIAN)==F_BIGENDIAN)?
192 " big endian":" little endian";
193 }
194 return res;
195 }
196
197
198 // /////////////////// BYTE 2 FLOAT /////////////////////////////////// //
199
200 private static final float twoPower7=128.0f;
201 private static final float twoPower15=32768.0f;
202 private static final float twoPower23=8388608.0f;
203 private static final float twoPower31=2147483648.0f;
204
205 private static final float invTwoPower7=1/twoPower7;
206 private static final float invTwoPower15=1/twoPower15;
207 private static final float invTwoPower23=1/twoPower23;
208 private static final float invTwoPower31=1/twoPower31;
209
210
211 /**
212 * Conversion function to convert an interleaved byte array to
213 * a List of interleaved float arrays. The float arrays will contain normalized
214 * samples in the range [-1.0f, +1.0f]. The input array
215 * provides bytes in the format specified in <code>format</code>.
216 * <p>
217 * Only PCM formats are accepted. The method will convert all
218 * byte values from
219 * <code>input[inByteOffset]</code> to
220 * <code>input[inByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
221 * to floats from
222 * <code>output(n)[outOffset]</code> to
223 * <code>output(n)[outOffset + frameCount - 1]</code>
224 *
225 * @param input the audio data in an byte array
226 * @param inByteOffset index in input where to start the conversion
227 * @param output list of float[] arrays which receive the converted audio data.
228 * if the list does not contain enough elements, or individual float arrays
229 * are not large enough, they are created.
230 * @param outOffset the start offset in <code>output</code>
231 * @param frameCount number of frames to be converted
232 * @param format the input format. Only packed PCM is allowed
233 * @throws IllegalArgumentException if one of the parameters is out of bounds
234 *
235 * @see #byte2floatInterleaved(byte[],int,float[],int,int,AudioFormat)
236 */
237 public static void byte2float(byte[] input, int inByteOffset,
238 List<float[]> output, int outOffset, int frameCount,
239 //List output, int outOffset, int frameCount,
240 AudioFormat format) {
241 for (int channel = 0; channel < format.getChannels(); channel++) {
242 float[] data;
243 if (output.size() < channel) {
244 data = new float[frameCount + outOffset];
245 output.add(data);
246 } else {
247 data = output.get(channel);
248 if (data.length < frameCount + outOffset) {
249 data = new float[frameCount + outOffset];
250 output.set(channel, data);
251 }
252 }
253
254 byte2floatGeneric(input, inByteOffset, format.getFrameSize(),
255 data, outOffset,
256 frameCount, format);
257 inByteOffset += format.getFrameSize() / format.getChannels();
258 }
259 }
260
261
262 /**
263 * Conversion function to convert an interleaved byte array to
264 * an interleaved float array. The float array will contain normalized
265 * samples in the range [-1.0f, +1.0f]. The input array
266 * provides bytes in the format specified in <code>format</code>.
267 * <p>
268 * Only PCM formats are accepted. The method will convert all
269 * byte values from
270 * <code>input[inByteOffset]</code> to
271 * <code>input[inByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
272 * to floats from
273 * <code>output[outOffset]</code> to
274 * <code>output[outOffset + (frameCount * format.getChannels()) - 1]</code>
275 *
276 * @param input the audio data in an byte array
277 * @param inByteOffset index in input where to start the conversion
278 * @param output the float array that receives the converted audio data
279 * @param outOffset the start offset in <code>output</code>
280 * @param frameCount number of frames to be converted
281 * @param format the input format. Only packed PCM is allowed
282 * @throws IllegalArgumentException if one of the parameters is out of bounds
283 *
284 * @see #byte2float(byte[],int,List,int,int,AudioFormat)
285 */
286 public static void byte2floatInterleaved(byte[] input, int inByteOffset,
287 float[] output, int outOffset, int frameCount,
288 AudioFormat format) {
289
290 byte2floatGeneric(input, inByteOffset, format.getFrameSize() / format.getChannels(),
291 output, outOffset, frameCount * format.getChannels(),
292 format);
293 }
294
295
296
297 /**
298 * Generic conversion function to convert a byte array to
299 * a float array.
300 * <p>
301 * Only PCM formats are accepted. The method will convert all
302 * bytes from
303 * <code>input[inByteOffset]</code> to
304 * <code>input[inByteOffset + (sampleCount * (inByteStep - 1)]</code>
305 * to samples from
306 * <code>output[outOffset]</code> to
307 * <code>output[outOffset+sampleCount-1]</code>.
308 * <p>
309 * The <code>format</code>'s channel count is ignored.
310 * <p>
311 * For mono data, set <code>inByteOffset</code> to <code>format.getFrameSize()</code>.<br>
312 * For converting interleaved input data, multiply <code>sampleCount</code>
313 * by the number of channels and set inByteStep to
314 * <code>format.getFrameSize() / format.getChannels()</code>.
315 *
316 * @param sampleCount number of samples to be written to output
317 * @param inByteStep how many bytes advance for each output sample in <code>output</code>.
318 * @throws IllegalArgumentException if one of the parameters is out of bounds
319 *
320 * @see #byte2floatInterleaved(byte[],int,float[],int,int,AudioFormat)
321 * @see #byte2float(byte[],int,List,int,int,AudioFormat)
322 */
323 static void byte2floatGeneric(byte[] input, int inByteOffset, int inByteStep,
324 float[] output, int outOffset, int sampleCount,
325 AudioFormat format) {
326 int formatType = getFormatType(format);
327
328 byte2floatGeneric(input, inByteOffset, inByteStep,
329 output, outOffset, sampleCount,
330 formatType);
331 }
332
333
334 /**
335 * Central conversion function from
336 * a byte array to a normalized float array. In order to accomodate
337 * interleaved and non-interleaved
338 * samples, this method takes inByteStep as parameter which
339 * can be used to flexibly convert the data.
340 * <p>
341 * E.g.:<br>
342 * mono->mono: inByteStep=format.getFrameSize()<br>
343 * interleaved_stereo->interleaved_stereo: inByteStep=format.getFrameSize()/2,
344 * sampleCount*2<br>
345 * stereo->2 mono arrays:<br>
346 * ---inByteOffset=0, outOffset=0, inByteStep=format.getFrameSize()<br>
347 * ---inByteOffset=format.getFrameSize()/2, outOffset=1, inByteStep=format.getFrameSize()<br>
348 */
349 static void byte2floatGeneric(byte[] input, int inByteOffset, int inByteStep,
350 float[] output, int outOffset, int sampleCount,
351 int formatType) {
352 //if (TDebug.TraceAudioConverter) {
353 // TDebug.out("FloatSampleTools.byte2floatGeneric, formatType="
354 // +formatType2Str(formatType));
355 //}
356 int endCount = outOffset + sampleCount;
357 int inIndex = inByteOffset;
358 for (int outIndex = outOffset; outIndex < endCount; outIndex++, inIndex+=inByteStep) {
359 // do conversion
360 switch (formatType) {
361 case CT_8S:
362 output[outIndex]=
363 ((float) input[inIndex])*invTwoPower7;
364 break;
365 case CT_8U:
366 output[outIndex]=
367 ((float) ((input[inIndex] & 0xFF)-128))*invTwoPower7;
368 break;
369 case CT_16SB:
370 output[outIndex]=
371 ((float) ((input[inIndex]<<8)
372 | (input[inIndex+1] & 0xFF)))*invTwoPower15;
373 break;
374 case CT_16SL:
375 output[outIndex]=
376 ((float) ((input[inIndex+1]<<8)
377 | (input[inIndex] & 0xFF)))*invTwoPower15;
378 break;
379 case CT_24SB:
380 output[outIndex]=
381 ((float) ((input[inIndex]<<16)
382 | ((input[inIndex+1] & 0xFF)<<8)
383 | (input[inIndex+2] & 0xFF)))*invTwoPower23;
384 break;
385 case CT_24SL:
386 output[outIndex]=
387 ((float) ((input[inIndex+2]<<16)
388 | ((input[inIndex+1] & 0xFF)<<8)
389 | (input[inIndex] & 0xFF)))*invTwoPower23;
390 break;
391 case CT_32SB:
392 output[outIndex]=
393 ((float) ((input[inIndex]<<24)
394 | ((input[inIndex+1] & 0xFF)<<16)
395 | ((input[inIndex+2] & 0xFF)<<8)
396 | (input[inIndex+3] & 0xFF)))*invTwoPower31;
397 break;
398 case CT_32SL:
399 output[outIndex]=
400 ((float) ((input[inIndex+3]<<24)
401 | ((input[inIndex+2] & 0xFF)<<16)
402 | ((input[inIndex+1] & 0xFF)<<8)
403 | (input[inIndex] & 0xFF)))*invTwoPower31;
404 break;
405 default:
406 throw new IllegalArgumentException
407 ("unsupported format="+formatType2Str(formatType));
408 }
409 }
410 }
411
412 // /////////////////// FLOAT 2 BYTE /////////////////////////////////// //
413
414 private static byte quantize8(float sample, float ditherBits) {
415 if (ditherBits!=0) {
416 sample+=random.nextFloat()*ditherBits;
417 }
418 if (sample>=127.0f) {
419 return (byte) 127;
420 } else if (sample<=-128.0f) {
421 return (byte) -128;
422 } else {
423 return (byte) (sample<0?(sample-0.5f):(sample+0.5f));
424 }
425 }
426
427 private static int quantize16(float sample, float ditherBits) {
428 if (ditherBits!=0) {
429 sample+=random.nextFloat()*ditherBits;
430 }
431 if (sample>=32767.0f) {
432 return 32767;
433 } else if (sample<=-32768.0f) {
434 return -32768;
435 } else {
436 return (int) (sample<0?(sample-0.5f):(sample+0.5f));
437 }
438 }
439
440 private static int quantize24(float sample, float ditherBits) {
441 if (ditherBits!=0) {
442 sample+=random.nextFloat()*ditherBits;
443 }
444 if (sample>=8388607.0f) {
445 return 8388607;
446 } else if (sample<=-8388608.0f) {
447 return -8388608;
448 } else {
449 return (int) (sample<0?(sample-0.5f):(sample+0.5f));
450 }
451 }
452
453 private static int quantize32(float sample, float ditherBits) {
454 if (ditherBits!=0) {
455 sample+=random.nextFloat()*ditherBits;
456 }
457 if (sample>=2147483647.0f) {
458 return 2147483647;
459 } else if (sample<=-2147483648.0f) {
460 return -2147483648;
461 } else {
462 return (int) (sample<0?(sample-0.5f):(sample+0.5f));
463 }
464 }
465
466
467 /**
468 * Conversion function to convert a non-interleaved float audio data to
469 * an interleaved byte array. The float arrays contains normalized
470 * samples in the range [-1.0f, +1.0f]. The output array
471 * will receive bytes in the format specified in <code>format</code>.
472 * Exactly <code>format.getChannels()</code> channels are converted
473 * regardless of the number of elements in <code>input</code>. If <code>input</code>
474 * does not provide enough channels, an </code>IllegalArgumentException<code> is thrown.
475 * <p>
476 * Only PCM formats are accepted. The method will convert all
477 * samples from <code>input(n)[inOffset]</code> to
478 * <code>input(n)[inOffset + frameCount - 1]</code>
479 * to byte values from <code>output[outByteOffset]</code> to
480 * <code>output[outByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
481 * <p>
482 * Dithering should be used when the output resolution is significantly
483 * lower than the original resolution. This includes if the original
484 * data was 16-bit and it is now converted to 8-bit, or if the
485 * data was generated in the float domain. No dithering need to be used
486 * if the original sample data was in e.g. 8-bit and the resulting output
487 * data has a higher resolution. If dithering is used, a sensitive value
488 * is DEFAULT_DITHER_BITS.
489 *
490 * @param input a List of float arrays with the input audio data
491 * @param inOffset index in the input arrays where to start the conversion
492 * @param output the byte array that receives the converted audio data
493 * @param outByteOffset the start offset in <code>output</code>
494 * @param frameCount number of frames to be converted.
495 * @param format the output format. Only packed PCM is allowed
496 * @param ditherBits if 0, do not dither. Otherwise the number of bits to be dithered
497 * @throws IllegalArgumentException if one of the parameters is out of bounds
498 *
499 * @see #DEFAULT_DITHER_BITS
500 * @see #float2byteInterleaved(float[],int,byte[],int,int,AudioFormat,float)
501 */
502 //public static void float2byte(List<float[]> input, int inOffset,
503 public static void float2byte(List input, int inOffset,
504 byte[] output, int outByteOffset,
505 int frameCount,
506 AudioFormat format, float ditherBits) {
507 for (int channel = 0; channel < format.getChannels(); channel++) {
508 float[] data = (float[]) input.get(channel);
509 float2byteGeneric(data, inOffset,
510 output, outByteOffset, format.getFrameSize(),
511 frameCount, format, ditherBits);
512 outByteOffset += format.getFrameSize() / format.getChannels();
513 }
514 }
515
516 /**
517 * Conversion function to convert an interleaved float array to
518 * an interleaved byte array. The float array contains normalized
519 * samples in the range [-1.0f, +1.0f]. The output array
520 * will receive bytes in the format specified in <code>format</code>.
521 * <p>
522 * Only PCM formats are accepted. The method will convert all
523 * samples from <code>input[inOffset]</code> to
524 * <code>input[inOffset + (frameCount * format.getChannels()) - 1]</code>
525 * to byte values from <code>output[outByteOffset]</code> to
526 * <code>output[outByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
527 * <p>
528 * Dithering should be used when the output resolution is significantly
529 * lower than the original resolution. This includes if the original
530 * data was 16-bit and it is now converted to 8-bit, or if the
531 * data was generated in the float domain. No dithering need to be used
532 * if the original sample data was in e.g. 8-bit and the resulting output
533 * data has a higher resolution. If dithering is used, a sensitive value
534 * is DEFAULT_DITHER_BITS.
535 *
536 * @param input the audio data in normalized samples
537 * @param inOffset index in input where to start the conversion
538 * @param output the byte array that receives the converted audio data
539 * @param outByteOffset the start offset in <code>output</code>
540 * @param frameCount number of frames to be converted.
541 * @param format the output format. Only packed PCM is allowed
542 * @param ditherBits if 0, do not dither. Otherwise the number of bits to be dithered
543 * @throws IllegalArgumentException if one of the parameters is out of bounds
544 *
545 * @see #DEFAULT_DITHER_BITS
546 * @see #float2byte(List,int,byte[],int,int,AudioFormat,float)
547 */
548 public static void float2byteInterleaved(float[] input, int inOffset,
549 byte[] output, int outByteOffset,
550 int frameCount,
551 AudioFormat format, float ditherBits) {
552 float2byteGeneric(input, inOffset,
553 output, outByteOffset, format.getFrameSize() / format.getChannels(),
554 frameCount * format.getChannels(),
555 format, ditherBits);
556 }
557
558
559
560 /**
561 * Generic conversion function to convert a float array to
562 * a byte array.
563 * <p>
564 * Only PCM formats are accepted. The method will convert all
565 * samples from <code>input[inOffset]</code> to
566 * <code>input[inOffset+sampleCount-1]</code>
567 * to byte values from <code>output[outByteOffset]</code> to
568 * <code>output[outByteOffset + (sampleCount * (outByteStep - 1)]</code>.
569 * <p>
570 * The <code>format</code>'s channel count is ignored.
571 * <p>
572 * For mono data, set <code>outByteOffset</code> to <code>format.getFrameSize()</code>.<br>
573 * For converting interleaved input data, multiply <code>sampleCount</code>
574 * by the number of channels and set outByteStep to
575 * <code>format.getFrameSize() / format.getChannels()</code>.
576 *
577 * @param sampleCount number of samples in input to be converted.
578 * @param outByteStep how many bytes advance for each input sample in <code>input</code>.
579 * @throws IllegalArgumentException if one of the parameters is out of bounds
580 *
581 * @see #float2byteInterleaved(float[],int,byte[],int,int,AudioFormat,float)
582 * @see #float2byte(List,int,byte[],int,int,AudioFormat,float)
583 */
584 static void float2byteGeneric(float[] input, int inOffset,
585 byte[] output, int outByteOffset, int outByteStep,
586 int sampleCount,
587 AudioFormat format, float ditherBits) {
588 int formatType = getFormatType(format);
589
590 float2byteGeneric(input, inOffset,
591 output, outByteOffset, outByteStep,
592 sampleCount,
593 formatType, ditherBits);
594 }
595
596
597 /**
598 * Central conversion function from normalized float array to
599 * a byte array. In order to accomodate interleaved and non-interleaved
600 * samples, this method takes outByteStep as parameter which
601 * can be used to flexibly convert the data.
602 * <p>
603 * E.g.:<br>
604 * mono->mono: outByteStep=format.getFrameSize()<br>
605 * interleaved stereo->interleaved stereo: outByteStep=format.getFrameSize()/2, sampleCount*2<br>
606 * 2 mono arrays->stereo:<br>
607 * ---inOffset=0, outByteOffset=0, outByteStep=format.getFrameSize()<br>
608 * ---inOffset=1, outByteOffset=format.getFrameSize()/2, outByteStep=format.getFrameSize()<br>
609 */
610 static void float2byteGeneric(float[] input, int inOffset,
611 byte[] output, int outByteOffset, int outByteStep,
612 int sampleCount, int formatType, float ditherBits) {
613 //if (TDebug.TraceAudioConverter) {
614 // TDebug.out("FloatSampleBuffer.float2byteGeneric, formatType="
615 // +"formatType2Str(formatType));
616 //}
617
618 if (inOffset < 0
619 || inOffset + sampleCount > input.length
620 || sampleCount < 0) {
621 throw new IllegalArgumentException("invalid input index: "
622 +"input.length="+input.length
623 +" inOffset="+inOffset
624 +" sampleCount="+sampleCount);
625 }
626 if (outByteOffset < 0
627 || outByteOffset + (sampleCount * outByteStep) > output.length
628 || outByteStep < getSampleSize(formatType)) {
629 throw new IllegalArgumentException("invalid output index: "
630 +"output.length="+output.length
631 +" outByteOffset="+outByteOffset
632 +" sampleCount="+sampleCount
633 +" format="+formatType2Str(formatType));
634 }
635
636 if (ditherBits!=0.0f && random==null) {
637 // create the random number generator for dithering
638 random=new Random();
639 }
640 int endSample = inOffset + sampleCount;
641 int iSample;
642 int outIndex = outByteOffset;
643 for (int inIndex = inOffset;
644 inIndex < endSample;
645 inIndex++, outIndex+=outByteStep) {
646 // do conversion
647 switch (formatType) {
648 case CT_8S:
649 output[outIndex]=quantize8(input[inIndex]*twoPower7, ditherBits);
650 break;
651 case CT_8U:
652 output[outIndex]=(byte) (quantize8((input[inIndex]*twoPower7), ditherBits)+128);
653 break;
654 case CT_16SB:
655 iSample=quantize16(input[inIndex]*twoPower15, ditherBits);
656 output[outIndex]=(byte) (iSample >> 8);
657 output[outIndex+1]=(byte) (iSample & 0xFF);
658 break;
659 case CT_16SL:
660 iSample=quantize16(input[inIndex]*twoPower15, ditherBits);
661 output[outIndex+1]=(byte) (iSample >> 8);
662 output[outIndex]=(byte) (iSample & 0xFF);
663 break;
664 case CT_24SB:
665 iSample=quantize24(input[inIndex]*twoPower23, ditherBits);
666 output[outIndex]=(byte) (iSample >> 16);
667 output[outIndex+1]=(byte) ((iSample >>> 8) & 0xFF);
668 output[outIndex+2]=(byte) (iSample & 0xFF);
669 break;
670 case CT_24SL:
671 iSample=quantize24(input[inIndex]*twoPower23, ditherBits);
672 output[outIndex+2]=(byte) (iSample >> 16);
673 output[outIndex+1]=(byte) ((iSample >>> 8) & 0xFF);
674 output[outIndex]=(byte) (iSample & 0xFF);
675 break;
676 case CT_32SB:
677 iSample=quantize32(input[inIndex]*twoPower31, ditherBits);
678 output[outIndex]=(byte) (iSample >> 24);
679 output[outIndex+1]=(byte) ((iSample >>> 16) & 0xFF);
680 output[outIndex+2]=(byte) ((iSample >>> 8) & 0xFF);
681 output[outIndex+3]=(byte) (iSample & 0xFF);
682 break;
683 case CT_32SL:
684 iSample=quantize32(input[inIndex]*twoPower31, ditherBits);
685 output[outIndex+3]=(byte) (iSample >> 24);
686 output[outIndex+2]=(byte) ((iSample >>> 16) & 0xFF);
687 output[outIndex+1]=(byte) ((iSample >>> 8) & 0xFF);
688 output[outIndex]=(byte) (iSample & 0xFF);
689 break;
690 default:
691 throw new IllegalArgumentException
692 ("unsupported format="+formatType2Str(formatType));
693 }
694 }
695 }
696}