/Users/lyon/j4p/src/sound/UlawCodec.java
|
1 package sound;
2
3 import futils.FileList;
4 import futils.Futil;
5 import futils.WildFilter;
6 import sun.audio.AudioData;
7 import sun.audio.AudioDataStream;
8 import sun.audio.AudioPlayer;
9 import sun.audio.AudioStream;
10
11 import java.awt.Container;
12 import java.awt.GridLayout;
13 import java.io.DataOutputStream;
14 import java.io.File;
15 import java.io.FileInputStream;
16 import java.io.FileOutputStream;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.net.MalformedURLException;
20 import java.net.URL;
21
22 public class UlawCodec {
23 private byte ulawData[];
24 private double doubleArray[];
25 private AudioDataStream audioDataStream = null;
26
27 //private AudioStream audioStream = null;
28
29 private final int samplingRate = 8000;
30
31
32
33 // exp_lut - a lookup table for quick natural logarithm
34 // transformation
35
36 private final static int
37 exp_lut[] = {0, 0, 1, 1, 2, 2, 2, 2,
38 3, 3, 3, 3, 3, 3, 3, 3,
39 4, 4, 4, 4, 4, 4, 4, 4,
40 4, 4, 4, 4, 4, 4, 4, 4,
41 5, 5, 5, 5, 5, 5, 5, 5,
42 5, 5, 5, 5, 5, 5, 5, 5,
43 5, 5, 5, 5, 5, 5, 5, 5,
44 5, 5, 5, 5, 5, 5, 5, 5,
45 6, 6, 6, 6, 6, 6, 6, 6,
46 6, 6, 6, 6, 6, 6, 6, 6,
47 6, 6, 6, 6, 6, 6, 6, 6,
48 6, 6, 6, 6, 6, 6, 6, 6,
49 6, 6, 6, 6, 6, 6, 6, 6,
50 6, 6, 6, 6, 6, 6, 6, 6,
51 6, 6, 6, 6, 6, 6, 6, 6,
52 6, 6, 6, 6, 6, 6, 6, 6,
53 7, 7, 7, 7, 7, 7, 7, 7,
54 7, 7, 7, 7, 7, 7, 7, 7,
55 7, 7, 7, 7, 7, 7, 7, 7,
56 7, 7, 7, 7, 7, 7, 7, 7,
57 7, 7, 7, 7, 7, 7, 7, 7,
58 7, 7, 7, 7, 7, 7, 7, 7,
59 7, 7, 7, 7, 7, 7, 7, 7,
60 7, 7, 7, 7, 7, 7, 7, 7,
61 7, 7, 7, 7, 7, 7, 7, 7,
62 7, 7, 7, 7, 7, 7, 7, 7,
63 7, 7, 7, 7, 7, 7, 7, 7,
64 7, 7, 7, 7, 7, 7, 7, 7,
65 7, 7, 7, 7, 7, 7, 7, 7,
66 7, 7, 7, 7, 7, 7, 7, 7,
67 7, 7, 7, 7, 7, 7, 7, 7,
68 7, 7, 7, 7, 7, 7, 7, 7};
69
70 public void echo() {
71 double linearSamples[] = computeDoubleArray();
72 Utils.echo(linearSamples);
73 }
74 // this junk....
75 public void delay() {
76 double s1, s2, s3;
77 int delay = 100;
78 int delay3 = 1000;
79 double[] doubleData = getDoubleArray();
80 for (int i = 0; i < doubleData.length; i++) {
81 s1 = doubleData[i];
82 s2 = 0;
83 s3 = 0;
84 if (i > delay) {
85 s2 = doubleData[i - delay];
86 }
87 if (i > delay3) {
88 s3 = doubleData[i - delay3];
89 }
90 doubleData[i] = (s3 + s2 + s1) / 3;
91 }
92 play();
93 }
94
95 public UlawCodec(byte ulawArrayOfByte[]) {
96 ulawData = ulawArrayOfByte;
97 }
98
99 /**
100 * Open the <code>fileName</code> and read in the data
101 * as if it were u-law encoded. Then turn it into linear
102 * PCM data.
103 *
104 * @param fileName
105 */
106 public void readAUFile(String fileName) {
107 // force recomputation
108 // of the doubleArray, as it is invalid
109 doubleArray = null;
110 try {
111 readUlawDataFromAFile(fileName);
112 } catch (Exception e) {
113 e.printStackTrace();
114 }
115 }
116
117 public static void main(String args[]) {
118 //playFromFile();
119 //playAuFiles(getAuFiles());
120 //showSampleData();
121 UlawCodec ulc = new UlawCodec();
122 ulc.play();
123 ulc.echo();
124 }
125
126 private void readUlawDataFromAFile(String fileName) throws IOException {
127 FileInputStream fis = new FileInputStream(fileName);
128 ulawData = readData(fis);
129 fis.close();
130 }
131
132 /**
133 * Reads in all the data at once, from any inputstream.
134 * Remember to close the InputStream when you are done.
135 *
136 * @param is
137 * @return Array of data
138 * @throws IOException
139 */
140 public static byte[] readData(InputStream is) throws IOException {
141 AudioStream as = new AudioStream(is);
142 // AudioStream constructor
143 // expects data stream from AU file as input
144 int length = as.getLength();
145 if (length < 0) return null;
146 byte b[] = new byte[length];
147 as.read(b, 0, length);
148 return b;
149 }
150
151 public static File[] getAuFiles() {
152 FileList fl = new FileList();
153 File f =
154 Futil.getReadDirFile("select a start file");
155 WildFilter wf = new WildFilter(".au");
156 fl.list(f, wf);
157 fl.print(); // todo will delete this later....
158 return fl.getFiles();
159 }
160
161 public static void playAuFiles(File f[]) {
162 for (int i = 0; i < f.length; i++) {
163 UlawCodec ulc = new UlawCodec(f[i].toString());
164 ulc.run();
165 }
166 }
167
168 public UlawCodec() {
169 readAUFile(Futil.getReadFileName("select an au file"));
170 }
171
172 /**
173 * Input a fully qualified file name
174 * use the play method to hear it.
175 *
176 * @param _fn
177 */
178 public UlawCodec(String _fn) {
179 String fileName = _fn;
180 readAUFile(fileName);
181 }
182
183 public UlawCodec(URL _url) {
184 try {
185 readAU(_url);
186 } catch (Exception e) {
187 }
188 }
189
190 // ---------------------------------------------------------------
191 //
192 // public UlawCodec(short linearData[]);
193 //
194 // This constructor can be used to produce u-law encoded ip.audio
195 // samples from an linerly encoded array of 16 bit signed integers
196 //
197 // ---------------------------------------------------------------
198
199 public UlawCodec(short linearArrayOfShort[]) {
200 ulawData =
201 new byte[linearArrayOfShort.length];
202 int max = 0;
203 int sample, sign, exponent, mantissa;
204
205 // now we need to find the sample of maximal amplitude
206 // then we can scale the data in such a way that the biggest
207 // sample will be 0x7FFF (max signed short)
208 for (int i = 0; i <
209 linearArrayOfShort.length; i++)
210 if (Math.abs(linearArrayOfShort[i]) >
211 max)
212 max = Math.abs(linearArrayOfShort[i]);
213 float factor = (float) 0x7FFF / max;
214 for (int i = 0; i <
215 linearArrayOfShort.length; i++) {
216 sample = (int) (linearArrayOfShort[i] * factor);
217
218 // lets calculate sign of the sample and its absolute value
219
220 sign = (sample >> 8) & 0x80;
221 if (sign != 0) sample = -sample;
222
223 // adding bias
224
225 sample = sample + 0x84;
226
227 // now the tricky part: quick logarithmic transform, so that smaller samples
228
229 // will be larger and larger samples smaller
230
231 exponent =
232 exp_lut[(sample >> 7) & 0xFF];
233 mantissa = (sample >> (exponent + 3)) &
234 0x0F;
235
236 // lets pack it into one byte
237
238 ulawData[i] =
239 (byte) ~(sign | (exponent << 4) |
240 mantissa);
241 }
242 }
243
244
245
246 // ---------------------------------------------------------------
247 //
248 // public UlawCodec(double linearData[]);
249 //
250 // This constructor can be used to produce u-law encoded ip.audio
251 // samples from an linerly encoded array of 64 bit signed signed
252 // floating point numbers ranged from -1 to 1
253 //
254 // ---------------------------------------------------------------
255
256 public UlawCodec(double linearArrayOfDouble[]) {
257 int sample, sign, exponent, mantissa;
258 ulawData =
259 new byte[linearArrayOfDouble.length];
260
261 // this metod is quite similar to UlawCodec(short linearData[])
262 // with exception that no scaling is done, the input is assumed
263 // be in the appropriate range. What if it is not? ... crash and burn
264
265 for (int i = 0; i <
266 linearArrayOfDouble.length; i++) {
267 sample =
268 (int) (linearArrayOfDouble[i] *
269 0x7FFF);
270 sign = (sample >> 8) & 0x80;
271 if (sign != 0) sample = -sample;
272 sample = sample + 0x84;
273 exponent =
274 exp_lut[(sample >> 7) & 0xFF];
275 mantissa = (sample >> (exponent + 3)) &
276 0x0F;
277 ulawData[i] =
278 (byte) ~(sign | (exponent << 4) |
279 mantissa);
280 }
281 }
282
283 public void readAU(URL url)
284 throws IOException {
285 InputStream is =
286 getInputStream(url);
287 readAU(is);
288 }
289
290 public InputStream getInputStream(URL url) {
291 InputStream is = null;
292 try {
293 url.openConnection();
294 is = url.openStream();
295 } catch (MalformedURLException e) {
296 e.printStackTrace();
297 } catch (IOException e) {
298 e.printStackTrace();
299 }
300 return is;
301 }
302
303 public void readAU(InputStream is)
304 throws IOException {
305 AudioStream audioStream =
306 new AudioStream(is);
307 ulawData =
308 new byte[audioStream.getLength()];
309 audioStream.read(ulawData,
310 0,
311 audioStream.getLength());
312 }
313
314 public void readAUFile() {
315 String fileName =
316 Futil.getReadFileName("Select an au file");
317 readAUFile(fileName);
318 }
319
320 public void writeAUFile() {
321 String fileName =
322 Futil.getWriteFile("select an au file").toString();
323 writeAUFile(fileName);
324 }
325
326
327
328 // ---------------------------------------------------------------
329
330 //
331
332 // public void writeAUFile(String name);
333
334 //
335
336 // This method saves the ip.audio data stored in this object into
337
338 // an AU file.
339
340 //
341
342 // ---------------------------------------------------------------
343
344 public void writeAUFile(String fileName) {
345 try {
346 FileOutputStream fos = new FileOutputStream(fileName);
347 DataOutputStream os = new
348 DataOutputStream(fos);
349
350 // not too much magic about it, just ".snd" ASCII string represented as
351
352 //integer
353
354 os.writeInt(0x2E736E64); // magic
355 os.writeInt(0x00000020); // offset of the data
356 os.writeInt(ulawData.length); // data size
357
358 // good old 8 bit per sample u-law encoded data format (code = 1)
359
360 os.writeInt(0x00000001); // format code
361 os.writeInt(0x00001F40); // sampling rate
362 os.writeInt(0x00000001); // channel count
363 os.writeInt(0x00000000); // reserved
364 os.writeInt(0x00000000); // reserved
365 os.write(ulawData,
366 0,
367 ulawData.length);
368 fos.close();
369 } catch (Exception e) {
370 System.out.println(e);
371 }
372 }
373
374 public void run() {
375 try {
376 stop();
377 AudioData audioData = new AudioData(ulawData);
378 audioDataStream =
379 new AudioDataStream(audioData);
380 AudioPlayer.player.start(audioDataStream);
381 Thread.sleep(ulawData.length / 8 + 100);
382 } catch (Exception e) {
383 }
384 }
385
386 public void play() {
387 stop();
388 if (ulawData == null) return;
389 AudioData audioData =
390 new AudioData(ulawData);
391 audioDataStream = new AudioDataStream(audioData);
392 AudioPlayer.player.start(audioDataStream);
393 }
394
395 private boolean isPlaying() {
396 return audioDataStream != null;
397 }
398
399 public void stop() {
400 if (isPlaying()) {
401 AudioPlayer.player.stop(audioDataStream);
402 audioDataStream = null;
403 }
404 }
405
406 public static void playFromFile() {
407 UlawCodec ulc = new UlawCodec();
408 ulc.play();
409 //ulc.writeAUFile();
410 }
411
412 public static void play(URL url) {
413 UlawCodec ulc = new UlawCodec(url);
414 ulc.play();
415 }
416
417 public double getFrequency() {
418 return 8000 / (2 * getDistanceBetweenMaxAndMinValues());
419 }
420
421 public void printLocationOfMaxValue() {
422 System.out.println("found max value at:" + getLocationOfMaxValue());
423 }
424
425 /**
426 * Starting at the startPoint, scan the data array for
427 * the value and return the location in the array.
428 * If it can't find the value, return -1;
429 *
430 * @param value to scan for
431 * @param startPoint location for the start point
432 * @return location or -1
433 */
434 public int getLocation(double value, int startPoint) {
435 double d[] = getDoubleArray();
436 for (int i = startPoint; i < d.length; i++)
437 if (d[i] == value)
438 return i;
439 return -1;
440 }
441
442 public void printDistanceBetweenMaxAndMinValues() {
443 System.out.println("getDistanceBetweenMaxAndMinValues=" +
444 getDistanceBetweenMaxAndMinValues());
445 }
446
447 public int getDistanceBetweenMaxAndMinValues() {
448 return Math.abs(getLocationOfMinValue() - getLocationOfMaxValue());
449 }
450
451 public int getLocationOfMinValue() {
452 return getLocation(getMinValue(), 0);
453 }
454
455 public int getLocationOfMaxValue() {
456 return getLocation(getMaxValue(), 0);
457 }
458
459 public void printMaxData() {
460 double maxValue = getMaxValue();
461 System.out.println("the max value is:" + maxValue);
462 }
463
464 public double getMinValue() {
465 double d[] = getDoubleArray();
466 double v = d[0];
467 for (int i = 0; i < d.length; i++)
468 if (d[i] < v)
469 v = d[i];
470 return v;
471 }
472
473 public double getMaxValue() {
474 double d[] = getDoubleArray();
475 double maxValue = d[0];
476 for (int i = 0; i < d.length; i++)
477 if (d[i] > maxValue)
478 maxValue = d[i];
479 return maxValue;
480 }
481
482 public static void showSampleData() {
483 UlawCodec ulc = new UlawCodec();
484 ulc.play();
485 OscopePanel osp = new OscopePanel(ulc.getDoubleArray());
486 gui.ClosableJFrame cf = new gui.ClosableJFrame();
487 Container c = cf.getContentPane();
488 c.add(osp);
489 c.setLayout(new GridLayout(1, 0));
490 cf.setSize(400, 400);
491 cf.show();
492 }
493
494 public void displayInternalData() {
495 play();
496 OscopePanel osp = new OscopePanel(getDoubleArray());
497 gui.ClosableJFrame cf = new gui.ClosableJFrame();
498 Container c = cf.getContentPane();
499 c.add(osp);
500 c.setLayout(new GridLayout(1, 0));
501 cf.setSize(400, 400);
502 cf.show();
503 }
504
505 public static void printSampleData() {
506 UlawCodec ulc = new UlawCodec();
507 ulc.play();
508 double d[] = ulc.getDoubleArray();
509 for (int i = 0; i < d.length; i++) {
510 int q = (int) (100 * d[i]);
511 System.out.print(q + " ");
512 if (i % 10 == 0)
513 System.out.println();
514 }
515 }
516
517 public byte[] getUlawData() {
518 return ulawData;
519 }
520
521 public void setUlawData(byte ulawArrayOfByte[]) {
522 ulawData = ulawArrayOfByte;
523 // force recomputation of the doubleArray
524 doubleArray = null;
525 }
526
527 public double[] getDoubleArray() {
528 if (doubleArray == null)
529 doubleArray = computeDoubleArray();
530 return doubleArray;
531 }
532
533 // out = decodeUlaw(in)
534
535 private double[] computeDoubleArray() {
536 double[] out = new double[ulawData.length];
537 for (int i = 0; i < ulawData.length; i++) {
538 out[i] =
539 Ulaw.ulawToDouble(ulawData[i]);
540 }
541 return out;
542 }
543
544 public int getLength() {
545 return ulawData.length;
546 }
547
548 public double getDuration() {
549 // Assume 8,000 samples per second
550 // then
551 // number_samples / 8,000 = number of seconds.
552 return ulawData.length / samplingRate;
553 }
554
555 public void reverseUlaw() {
556 int l = ulawData.length;
557 int i;
558 byte tmp;
559 for (i = 0; i < l / 2; i++) {
560 tmp = ulawData[i];
561 ulawData[i] = ulawData[l - i - 1];
562 ulawData[l - i - 1] = tmp;
563 }
564 doubleArray = null;
565 }
566 }