/Users/lyon/j4p/src/sound/soundDemo/CapturePlaybackPanel.java
|
1 package sound.soundDemo;
2
3 /*
4 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
5 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6 */
7
8
9 import javax.sound.sampled.*;
10 import javax.swing.*;
11 import javax.swing.border.BevelBorder;
12 import javax.swing.border.CompoundBorder;
13 import javax.swing.border.EmptyBorder;
14 import javax.swing.border.SoftBevelBorder;
15 import java.awt.*;
16 import java.awt.event.ActionEvent;
17 import java.awt.event.ActionListener;
18 import java.awt.event.WindowAdapter;
19 import java.awt.event.WindowEvent;
20 import java.awt.font.FontRenderContext;
21 import java.awt.font.LineBreakMeasurer;
22 import java.awt.font.TextAttribute;
23 import java.awt.font.TextLayout;
24 import java.awt.geom.Line2D;
25 import java.io.ByteArrayInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.File;
28 import java.io.IOException;
29 import java.text.AttributedCharacterIterator;
30 import java.text.AttributedString;
31 import java.util.Enumeration;
32 import java.util.Vector;
33
34
35 /**
36 * Capture/Playback sample. Record audio in different formats
37 * and then playback the recorded audio. The captured audio can
38 * be saved either as a WAVE, AU or AIFF. Or load an audio file
39 * for streaming playback.
40 *
41 * @version @(#)CapturePlaybackPanel.java 1.12 02/02/06
42 * @author Brian Lichtenwalter
43 */
44 public class CapturePlaybackPanel extends JPanel
45 implements ActionListener, ControlContext {
46
47 private final int bufSize = 16384;
48
49 private FormatControls formatControls = new FormatControls();
50 private Capture capture = new Capture();
51 private Playback playback = new Playback();
52
53 private AudioInputStream audioInputStream;
54 private SamplingGraph samplingGraph;
55
56 private JButton playB, captB, pausB, loadB;
57 private JButton auB, aiffB, waveB;
58 private JTextField textField;
59
60 private String fileName = "untitled";
61 private String errStr;
62 private double duration, seconds;
63 private File file;
64 private Vector graphicLineData = new Vector();
65
66
67 public CapturePlaybackPanel() {
68 setLayout(new BorderLayout());
69 EmptyBorder eb = new EmptyBorder(5, 5, 5, 5);
70 SoftBevelBorder sbb = new SoftBevelBorder(SoftBevelBorder.LOWERED);
71 setBorder(new EmptyBorder(5, 5, 5, 5));
72
73 JPanel p1 = new JPanel();
74 p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
75 p1.add(formatControls);
76
77 JPanel buttonPanel = new JPanel();
78 buttonPanel.setBorder(sbb);
79 buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
80
81 JPanel buttonsPanel = new JPanel();
82 buttonsPanel.setBorder(new EmptyBorder(10, 0, 5, 0));
83 playB = addButton("Play", buttonsPanel, false);
84 captB = addButton("Record", buttonsPanel, true);
85 pausB = addButton("Pause", buttonsPanel, false);
86 loadB = addButton("Load...", buttonsPanel, true);
87 buttonPanel.add(buttonsPanel);
88
89 JPanel samplingPanel = new JPanel(new BorderLayout());
90 eb = new EmptyBorder(10, 20, 20, 20);
91 samplingPanel.setBorder(new CompoundBorder(eb, sbb));
92 samplingPanel.add(samplingGraph = new SamplingGraph());
93 buttonPanel.add(samplingPanel);
94
95 JPanel savePanel = new JPanel();
96 savePanel.setLayout(new BoxLayout(savePanel, BoxLayout.Y_AXIS));
97
98 JPanel saveTFpanel = new JPanel();
99 saveTFpanel.add(new JLabel("File to save: "));
100 saveTFpanel.add(textField = new JTextField(fileName));
101 textField.setPreferredSize(new Dimension(140, 25));
102 savePanel.add(saveTFpanel);
103
104 JPanel saveBpanel = new JPanel();
105 auB = addButton("Save AU", saveBpanel, false);
106 aiffB = addButton("Save AIFF", saveBpanel, false);
107 waveB = addButton("Save WAVE", saveBpanel, false);
108 savePanel.add(saveBpanel);
109
110 buttonPanel.add(savePanel);
111
112 p1.add(buttonPanel);
113 add(p1);
114 }
115
116
117 public void open() {
118 }
119
120
121 public void close() {
122 if (playback.thread != null) {
123 playB.doClick(0);
124 }
125 if (capture.thread != null) {
126 captB.doClick(0);
127 }
128 }
129
130
131 private JButton addButton(String name, JPanel p, boolean state) {
132 JButton b = new JButton(name);
133 b.addActionListener(this);
134 b.setEnabled(state);
135 p.add(b);
136 return b;
137 }
138
139
140 public void actionPerformed(ActionEvent e) {
141 Object obj = e.getSource();
142 if (obj.equals(auB)) {
143 saveToFile(textField.getText().trim(), AudioFileFormat.Type.AU);
144 } else if (obj.equals(aiffB)) {
145 saveToFile(textField.getText().trim(), AudioFileFormat.Type.AIFF);
146 } else if (obj.equals(waveB)) {
147 saveToFile(textField.getText().trim(), AudioFileFormat.Type.WAVE);
148 } else if (obj.equals(playB)) {
149 if (playB.getText().startsWith("Play")) {
150 playback.start();
151 samplingGraph.start();
152 captB.setEnabled(false);
153 pausB.setEnabled(true);
154 playB.setText("Stop");
155 } else {
156 playback.stop();
157 samplingGraph.stop();
158 captB.setEnabled(true);
159 pausB.setEnabled(false);
160 playB.setText("Play");
161 }
162 } else if (obj.equals(captB)) {
163 if (captB.getText().startsWith("Record")) {
164 file = null;
165 capture.start();
166 fileName = "untitled";
167 samplingGraph.start();
168 loadB.setEnabled(false);
169 playB.setEnabled(false);
170 pausB.setEnabled(true);
171 auB.setEnabled(false);
172 aiffB.setEnabled(false);
173 waveB.setEnabled(false);
174 captB.setText("Stop");
175 } else {
176 graphicLineData.removeAllElements();
177 capture.stop();
178 samplingGraph.stop();
179 loadB.setEnabled(true);
180 playB.setEnabled(true);
181 pausB.setEnabled(false);
182 auB.setEnabled(true);
183 aiffB.setEnabled(true);
184 waveB.setEnabled(true);
185 captB.setText("Record");
186 }
187 } else if (obj.equals(pausB)) {
188 if (pausB.getText().startsWith("Pause")) {
189 if (capture.thread != null) {
190 capture.line.stop();
191 } else {
192 if (playback.thread != null) {
193 playback.line.stop();
194 }
195 }
196 pausB.setText("Resume");
197 } else {
198 if (capture.thread != null) {
199 capture.line.start();
200 } else {
201 if (playback.thread != null) {
202 playback.line.start();
203 }
204 }
205 pausB.setText("Pause");
206 }
207 } else if (obj.equals(loadB)) {
208 try {
209 File file = new File(System.getProperty("user.dir"));
210 JFileChooser fc = new JFileChooser(file);
211 fc.setFileFilter(new javax.swing.filechooser.FileFilter() {
212 public boolean accept(File f) {
213 if (f.isDirectory()) {
214 return true;
215 }
216 String name = f.getName();
217 if (name.endsWith(".au") || name.endsWith(".wav") || name.endsWith(".aiff") || name.endsWith(".aif")) {
218 return true;
219 }
220 return false;
221 }
222
223 public String getDescription() {
224 return ".au, .wav, .aif";
225 }
226 });
227
228 if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
229 createAudioInputStream(fc.getSelectedFile(), true);
230 }
231 } catch (SecurityException ex) {
232 JavaSound.showInfoDialog();
233 ex.printStackTrace();
234 } catch (Exception ex) {
235 ex.printStackTrace();
236 }
237 }
238 }
239
240
241 public void createAudioInputStream(File file, boolean updateComponents) {
242 if (file != null && file.isFile()) {
243 try {
244 this.file = file;
245 errStr = null;
246 audioInputStream = AudioSystem.getAudioInputStream(file);
247 playB.setEnabled(true);
248 fileName = file.getName();
249 long milliseconds = (long) ((audioInputStream.getFrameLength() * 1000) / audioInputStream.getFormat().getFrameRate());
250 duration = milliseconds / 1000.0;
251 auB.setEnabled(true);
252 aiffB.setEnabled(true);
253 waveB.setEnabled(true);
254 if (updateComponents) {
255 formatControls.setFormat(audioInputStream.getFormat());
256 samplingGraph.createWaveForm(null);
257 }
258 } catch (Exception ex) {
259 reportStatus(ex.toString());
260 }
261 } else {
262 reportStatus("Audio file required.");
263 }
264 }
265
266
267 public void saveToFile(String name, AudioFileFormat.Type fileType) {
268
269 if (audioInputStream == null) {
270 reportStatus("No loaded audio to save");
271 return;
272 } else if (file != null) {
273 createAudioInputStream(file, false);
274 }
275
276 // reset to the beginnning of the captured data
277 try {
278 audioInputStream.reset();
279 } catch (Exception e) {
280 reportStatus("Unable to reset stream " + e);
281 return;
282 }
283
284 File file = new File(fileName = name);
285 try {
286 if (AudioSystem.write(audioInputStream, fileType, file) == -1) {
287 throw new IOException("Problems writing to file");
288 }
289 } catch (Exception ex) {
290 reportStatus(ex.toString());
291 }
292 samplingGraph.repaint();
293 }
294
295
296 private void reportStatus(String msg) {
297 if ((errStr = msg) != null) {
298 System.out.println(errStr);
299 samplingGraph.repaint();
300 }
301 }
302
303
304 /**
305 * Write data to the OutputChannel.
306 */
307 public class Playback implements Runnable {
308
309 SourceDataLine line;
310 Thread thread;
311
312 public void start() {
313 errStr = null;
314 thread = new Thread(this);
315 thread.setName("Playback");
316 thread.start();
317 }
318
319 public void stop() {
320 thread = null;
321 }
322
323 private void shutDown(String message) {
324 if ((errStr = message) != null) {
325 System.err.println(errStr);
326 samplingGraph.repaint();
327 }
328 if (thread != null) {
329 thread = null;
330 samplingGraph.stop();
331 captB.setEnabled(true);
332 pausB.setEnabled(false);
333 playB.setText("Play");
334 }
335 }
336
337 public void run() {
338
339 // reload the file if loaded by file
340 if (file != null) {
341 createAudioInputStream(file, false);
342 }
343
344 // make sure we have something to play
345 if (audioInputStream == null) {
346 shutDown("No loaded audio to play back");
347 return;
348 }
349 // reset to the beginnning of the stream
350 try {
351 audioInputStream.reset();
352 } catch (Exception e) {
353 shutDown("Unable to reset the stream\n" + e);
354 return;
355 }
356
357 // get an AudioInputStream of the desired format for playback
358 AudioFormat format = formatControls.getFormat();
359 AudioInputStream playbackInputStream = AudioSystem.getAudioInputStream(format, audioInputStream);
360
361 if (playbackInputStream == null) {
362 shutDown("Unable to convert stream of format " + audioInputStream + " to format " + format);
363 return;
364 }
365
366 // define the required attributes for our line,
367 // and make sure a compatible line is supported.
368
369 DataLine.Info info = new DataLine.Info(SourceDataLine.class,
370 format);
371 if (!AudioSystem.isLineSupported(info)) {
372 shutDown("Line matching " + info + " not supported.");
373 return;
374 }
375
376 // get and open the source data line for playback.
377
378 try {
379 line = (SourceDataLine) AudioSystem.getLine(info);
380 line.open(format, bufSize);
381 } catch (LineUnavailableException ex) {
382 shutDown("Unable to open the line: " + ex);
383 return;
384 }
385
386 // play back the captured audio data
387
388 int frameSizeInBytes = format.getFrameSize();
389 int bufferLengthInFrames = line.getBufferSize() / 8;
390 int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
391 byte[] data = new byte[bufferLengthInBytes];
392 int numBytesRead = 0;
393
394 // start the source data line
395 line.start();
396
397 while (thread != null) {
398 try {
399 if ((numBytesRead = playbackInputStream.read(data)) == -1) {
400 break;
401 }
402 int numBytesRemaining = numBytesRead;
403 while (numBytesRemaining > 0) {
404 numBytesRemaining -= line.write(data, 0, numBytesRemaining);
405 }
406 } catch (Exception e) {
407 shutDown("Error during playback: " + e);
408 break;
409 }
410 }
411 // we reached the end of the stream. let the data play out, then
412 // stop and close the line.
413 if (thread != null) {
414 line.drain();
415 }
416 line.stop();
417 line.close();
418 line = null;
419 shutDown(null);
420 }
421 } // End class Playback
422
423
424 /**
425 * Reads data from the input channel and writes to the output stream
426 */
427 class Capture implements Runnable {
428
429 TargetDataLine line;
430 Thread thread;
431
432 public void start() {
433 errStr = null;
434 thread = new Thread(this);
435 thread.setName("Capture");
436 thread.start();
437 }
438
439 public void stop() {
440 thread = null;
441 }
442
443 private void shutDown(String message) {
444 if ((errStr = message) != null && thread != null) {
445 thread = null;
446 samplingGraph.stop();
447 loadB.setEnabled(true);
448 playB.setEnabled(true);
449 pausB.setEnabled(false);
450 auB.setEnabled(true);
451 aiffB.setEnabled(true);
452 waveB.setEnabled(true);
453 captB.setText("Record");
454 System.err.println(errStr);
455 samplingGraph.repaint();
456 }
457 }
458
459 public void run() {
460
461 duration = 0;
462 audioInputStream = null;
463
464 // define the required attributes for our line,
465 // and make sure a compatible line is supported.
466
467 AudioFormat format = formatControls.getFormat();
468 DataLine.Info info = new DataLine.Info(TargetDataLine.class,
469 format);
470
471 if (!AudioSystem.isLineSupported(info)) {
472 shutDown("Line matching " + info + " not supported.");
473 return;
474 }
475
476 // get and open the target data line for capture.
477
478 try {
479 line = (TargetDataLine) AudioSystem.getLine(info);
480 line.open(format, line.getBufferSize());
481 } catch (LineUnavailableException ex) {
482 shutDown("Unable to open the line: " + ex);
483 return;
484 } catch (SecurityException ex) {
485 shutDown(ex.toString());
486 JavaSound.showInfoDialog();
487 return;
488 } catch (Exception ex) {
489 shutDown(ex.toString());
490 return;
491 }
492
493 // play back the captured audio data
494 ByteArrayOutputStream out = new ByteArrayOutputStream();
495 int frameSizeInBytes = format.getFrameSize();
496 int bufferLengthInFrames = line.getBufferSize() / 8;
497 int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
498 byte[] data = new byte[bufferLengthInBytes];
499 int numBytesRead;
500
501 line.start();
502
503 while (thread != null) {
504 if ((numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) {
505 break;
506 }
507 out.write(data, 0, numBytesRead);
508 }
509
510 // we reached the end of the stream. stop and close the line.
511 line.stop();
512 line.close();
513 line = null;
514
515 // stop and close the output stream
516 try {
517 out.flush();
518 out.close();
519 } catch (IOException ex) {
520 ex.printStackTrace();
521 }
522
523 // load bytes into the audio input stream for playback
524
525 byte audioBytes[] = out.toByteArray();
526 ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);
527 audioInputStream = new AudioInputStream(bais, format, audioBytes.length / frameSizeInBytes);
528
529 long milliseconds = (long) ((audioInputStream.getFrameLength() * 1000) / format.getFrameRate());
530 duration = milliseconds / 1000.0;
531
532 try {
533 audioInputStream.reset();
534 } catch (Exception ex) {
535 ex.printStackTrace();
536 return;
537 }
538
539 samplingGraph.createWaveForm(audioBytes);
540 }
541 } // End class Capture
542
543
544 /**
545 * Controls for the AudioFormat.
546 */
547 class FormatControls extends JPanel {
548
549 Vector groups = new Vector();
550 JToggleButton linrB, ulawB, alawB, rate8B, rate11B, rate16B, rate22B, rate44B;
551 JToggleButton size8B, size16B, signB, unsignB, litB, bigB, monoB,sterB;
552
553 public FormatControls() {
554 setLayout(new GridLayout(0, 1));
555 EmptyBorder eb = new EmptyBorder(0, 0, 0, 5);
556 BevelBorder bb = new BevelBorder(BevelBorder.LOWERED);
557 CompoundBorder cb = new CompoundBorder(eb, bb);
558 setBorder(new CompoundBorder(cb, new EmptyBorder(8, 5, 5, 5)));
559 JPanel p1 = new JPanel();
560 ButtonGroup encodingGroup = new ButtonGroup();
561 linrB = addToggleButton(p1, encodingGroup, "linear", true);
562 ulawB = addToggleButton(p1, encodingGroup, "ulaw", false);
563 alawB = addToggleButton(p1, encodingGroup, "alaw", false);
564 add(p1);
565 groups.addElement(encodingGroup);
566
567 JPanel p2 = new JPanel();
568 JPanel p2b = new JPanel();
569 ButtonGroup sampleRateGroup = new ButtonGroup();
570 rate8B = addToggleButton(p2, sampleRateGroup, "8000", false);
571 rate11B = addToggleButton(p2, sampleRateGroup, "11025", false);
572 rate16B = addToggleButton(p2b, sampleRateGroup, "16000", false);
573 rate22B = addToggleButton(p2b, sampleRateGroup, "22050", false);
574 rate44B = addToggleButton(p2b, sampleRateGroup, "44100", true);
575 add(p2);
576 add(p2b);
577 groups.addElement(sampleRateGroup);
578
579 JPanel p3 = new JPanel();
580 ButtonGroup sampleSizeInBitsGroup = new ButtonGroup();
581 size8B = addToggleButton(p3, sampleSizeInBitsGroup, "8", false);
582 size16B = addToggleButton(p3, sampleSizeInBitsGroup, "16", true);
583 add(p3);
584 groups.addElement(sampleSizeInBitsGroup);
585
586 JPanel p4 = new JPanel();
587 ButtonGroup signGroup = new ButtonGroup();
588 signB = addToggleButton(p4, signGroup, "signed", true);
589 unsignB = addToggleButton(p4, signGroup, "unsigned", false);
590 add(p4);
591 groups.addElement(signGroup);
592
593 JPanel p5 = new JPanel();
594 ButtonGroup endianGroup = new ButtonGroup();
595 litB = addToggleButton(p5, endianGroup, "little endian", false);
596 bigB = addToggleButton(p5, endianGroup, "big endian", true);
597 add(p5);
598 groups.addElement(endianGroup);
599
600 JPanel p6 = new JPanel();
601 ButtonGroup channelsGroup = new ButtonGroup();
602 monoB = addToggleButton(p6, channelsGroup, "mono", false);
603 sterB = addToggleButton(p6, channelsGroup, "stereo", true);
604 add(p6);
605 groups.addElement(channelsGroup);
606 }
607
608 private JToggleButton addToggleButton(JPanel p, ButtonGroup g,
609 String name, boolean state) {
610 JToggleButton b = new JToggleButton(name, state);
611 p.add(b);
612 g.add(b);
613 return b;
614 }
615
616 public AudioFormat getFormat() {
617
618 Vector v = new Vector(groups.size());
619 for (int i = 0; i < groups.size(); i++) {
620 ButtonGroup g = (ButtonGroup) groups.get(i);
621 for (Enumeration e = g.getElements(); e.hasMoreElements();) {
622 AbstractButton b = (AbstractButton) e.nextElement();
623 if (b.isSelected()) {
624 v.add(b.getText());
625 break;
626 }
627 }
628 }
629
630 AudioFormat.Encoding encoding = AudioFormat.Encoding.ULAW;
631 String encString = (String) v.get(0);
632 float rate = Float.valueOf((String) v.get(1)).floatValue();
633 int sampleSize = Integer.valueOf((String) v.get(2)).intValue();
634 String signedString = (String) v.get(3);
635 boolean bigEndian = ((String) v.get(4)).startsWith("big");
636 int channels = (v.get(5)).equals("mono") ? 1 : 2;
637
638 if (encString.equals("linear")) {
639 if (signedString.equals("signed")) {
640 encoding = AudioFormat.Encoding.PCM_SIGNED;
641 } else {
642 encoding = AudioFormat.Encoding.PCM_UNSIGNED;
643 }
644 } else if (encString.equals("alaw")) {
645 encoding = AudioFormat.Encoding.ALAW;
646 }
647 return new AudioFormat(encoding, rate, sampleSize,
648 channels, (sampleSize / 8) * channels, rate, bigEndian);
649 }
650
651
652 public void setFormat(AudioFormat format) {
653 AudioFormat.Encoding type = format.getEncoding();
654 if (type == AudioFormat.Encoding.ULAW) {
655 ulawB.doClick();
656 } else if (type == AudioFormat.Encoding.ALAW) {
657 alawB.doClick();
658 } else if (type == AudioFormat.Encoding.PCM_SIGNED) {
659 linrB.doClick();
660 signB.doClick();
661 } else if (type == AudioFormat.Encoding.PCM_UNSIGNED) {
662 linrB.doClick();
663 unsignB.doClick();
664 }
665 float rate = format.getFrameRate();
666 if (rate == 8000) {
667 rate8B.doClick();
668 } else if (rate == 11025) {
669 rate11B.doClick();
670 } else if (rate == 16000) {
671 rate16B.doClick();
672 } else if (rate == 22050) {
673 rate22B.doClick();
674 } else if (rate == 44100) {
675 rate44B.doClick();
676 }
677 switch (format.getSampleSizeInBits()) {
678 case 8:
679 size8B.doClick();
680 break;
681 case 16:
682 size16B.doClick();
683 break;
684 }
685 if (format.isBigEndian()) {
686 bigB.doClick();
687 } else {
688 litB.doClick();
689 }
690 if (format.getChannels() == 1) {
691 monoB.doClick();
692 } else {
693 sterB.doClick();
694 }
695 }
696 } // End class FormatControls
697
698 /**
699 * Render a WaveForm.
700 */
701 class SamplingGraph extends JPanel implements Runnable {
702
703 private Thread thread;
704 //private Font font10 = new Font("serif", Font.PLAIN, 10);
705 private Font font12 = new Font("serif", Font.PLAIN, 12);
706 Color jfcBlue = new Color(204, 204, 255);
707 Color pink = new Color(255, 175, 175);
708
709
710 public SamplingGraph() {
711 setBackground(new Color(20, 20, 20));
712 }
713
714
715 public void createWaveForm(byte[] audioBytes) {
716
717 graphicLineData.removeAllElements(); // clear the old vector
718
719 AudioFormat format = audioInputStream.getFormat();
720 if (audioBytes == null) {
721 try {
722 audioBytes = new byte[
723 (int) (audioInputStream.getFrameLength()
724 * format.getFrameSize())];
725 audioInputStream.read(audioBytes);
726 } catch (Exception ex) {
727 reportStatus(ex.toString());
728 return;
729 }
730 }
731
732 Dimension d = getSize();
733 int w = d.width;
734 int h = d.height - 15;
735 int[] audioData = null;
736 audioData = getAudioData(format, audioBytes, audioData);
737 int frames_per_pixel = audioBytes.length / format.getFrameSize() / w;
738 byte my_byte = 0;
739 double y_last = 0;
740 int numChannels = format.getChannels();
741 for (double x = 0; x < w && audioData != null; x++) {
742 int idx = (int) (frames_per_pixel * numChannels * x);
743 if (format.getSampleSizeInBits() == 8) {
744 my_byte = (byte) audioData[idx];
745 } else {
746 my_byte = (byte) (128 * audioData[idx] / 32768);
747 }
748 double y_new = (double) (h * (128 - my_byte) / 256);
749 graphicLineData.add(new Line2D.Double(x, y_last, x, y_new));
750 y_last = y_new;
751 }
752
753 repaint();
754 }
755
756 private int[] getAudioData(AudioFormat format, byte[] audioBytes, int[] audioData) {
757 if (format.getSampleSizeInBits() == 16) {
758 int nlengthInSamples = audioBytes.length / 2;
759 audioData = new int[nlengthInSamples];
760 if (format.isBigEndian()) {
761 for (int i = 0; i < nlengthInSamples; i++) {
762 /* First byte is MSB (high order) */
763 int MSB = (int) audioBytes[2 * i];
764 /* Second byte is LSB (low order) */
765 int LSB = (int) audioBytes[2 * i + 1];
766 audioData[i] = MSB << 8 | (255 & LSB);
767 }
768 } else {
769 for (int i = 0; i < nlengthInSamples; i++) {
770 /* First byte is LSB (low order) */
771 int LSB = (int) audioBytes[2 * i];
772 /* Second byte is MSB (high order) */
773 int MSB = (int) audioBytes[2 * i + 1];
774 audioData[i] = MSB << 8 | (255 & LSB);
775 }
776 }
777 } else if (format.getSampleSizeInBits() == 8) {
778 int nlengthInSamples = audioBytes.length;
779 audioData = new int[nlengthInSamples];
780 if (format.getEncoding().toString().startsWith("PCM_SIGN")) {
781 for (int i = 0; i < audioBytes.length; i++) {
782 audioData[i] = audioBytes[i];
783 }
784 } else {
785 for (int i = 0; i < audioBytes.length; i++) {
786 audioData[i] = audioBytes[i] - 128;
787 }
788 }
789 }
790 return audioData;
791 }
792
793 public void paint(Graphics g) {
794
795 Dimension d = getSize();
796 int w = d.width;
797 int h = d.height;
798 int INFOPAD = 15;
799
800 Graphics2D g2 = (Graphics2D) g;
801 g2.setBackground(getBackground());
802 g2.clearRect(0, 0, w, h);
803 g2.setColor(Color.white);
804 g2.fillRect(0, h - INFOPAD, w, INFOPAD);
805
806 if (errStr != null) {
807 g2.setColor(jfcBlue);
808 g2.setFont(new Font("serif", Font.BOLD, 18));
809 g2.drawString("ERROR", 5, 20);
810 AttributedString as = new AttributedString(errStr);
811 as.addAttribute(TextAttribute.FONT, font12, 0, errStr.length());
812 AttributedCharacterIterator aci = as.getIterator();
813 FontRenderContext frc = g2.getFontRenderContext();
814 LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
815 float x = 5, y = 25;
816 lbm.setPosition(0);
817 while (lbm.getPosition() < errStr.length()) {
818 TextLayout tl = lbm.nextLayout(w - x - 5);
819 if (!tl.isLeftToRight()) {
820 x = w - tl.getAdvance();
821 }
822 tl.draw(g2, x, y += tl.getAscent());
823 y += tl.getDescent() + tl.getLeading();
824 }
825 } else if (capture.thread != null) {
826 g2.setColor(Color.black);
827 g2.setFont(font12);
828 g2.drawString("Length: " + String.valueOf(seconds), 3, h - 4);
829 } else {
830 g2.setColor(Color.black);
831 g2.setFont(font12);
832 g2.drawString("File: " + fileName + " Length: " + String.valueOf(duration) + " Position: " + String.valueOf(seconds), 3, h - 4);
833 drawData2(g2);
834 }
835 }
836
837 private void drawData2(Graphics2D g2) {
838 if (audioInputStream != null) {
839 // .. render sampling graph ..
840 g2.setColor(jfcBlue);
841 for (int i = 1; i < graphicLineData.size(); i++) {
842 g2.draw((Line2D) graphicLineData.get(i));
843 }
844 //drawData(w, g2, h, INFOPAD);
845 }
846 }
847
848 private void drawData(int w, Graphics2D g2, int h, int INFOPAD) {
849 // .. draw current position ..
850 if (seconds != 0) {
851 double loc = seconds / duration * w;
852 g2.setColor(pink);
853 g2.setStroke(new BasicStroke(3));
854 g2.draw(new Line2D.Double(loc, 0, loc, h - INFOPAD - 2));
855 }
856 }
857
858 public void start() {
859 thread = new Thread(this);
860 thread.setName("SamplingGraph");
861 thread.start();
862 seconds = 0;
863 }
864
865 public void stop() {
866 if (thread != null) {
867 thread.interrupt();
868 }
869 thread = null;
870 }
871
872 public void run() {
873 seconds = 0;
874 while (thread != null) {
875 if ((playback.line != null) && (playback.line.isOpen())) {
876
877 long milliseconds = (playback.line.getMicrosecondPosition() / 1000);
878 seconds = milliseconds / 1000.0;
879 } else if ((capture.line != null) && (capture.line.isActive())) {
880
881 long milliseconds = (capture.line.getMicrosecondPosition() / 1000);
882 seconds = milliseconds / 1000.0;
883 }
884
885 try {
886 Thread.sleep(100);
887 } catch (Exception e) {
888 break;
889 }
890
891 repaint();
892
893 while ((capture.line != null && !capture.line.isActive()) ||
894 (playback.line != null && !playback.line.isOpen())) {
895 try {
896 Thread.sleep(10);
897 } catch (Exception e) {
898 break;
899 }
900 }
901 }
902 seconds = 0;
903 repaint();
904 }
905 } // End class SamplingGraph
906
907
908 public static void main(String s[]) {
909 CapturePlaybackPanel capturePlaybackPanel = new CapturePlaybackPanel();
910 capturePlaybackPanel.open();
911 JFrame f = new JFrame("Capture/Playback");
912 f.addWindowListener(new WindowAdapter() {
913 public void windowClosing(WindowEvent e) {
914 System.exit(0);
915 }
916 });
917 f.getContentPane().add("Center", capturePlaybackPanel);
918 f.pack();
919 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
920 int w = 720;
921 int h = 340;
922 f.setLocation(screenSize.width / 2 - w / 2, screenSize.height / 2 - h / 2);
923 f.setSize(w, h);
924 f.show();
925 }
926
927 public int getBufSize() {
928 return bufSize;
929 }
930
931 public FormatControls getFormatControls() {
932 return formatControls;
933 }
934
935 public Capture getCapture() {
936 return capture;
937 }
938
939 public Playback getPlayback() {
940 return playback;
941 }
942
943 public AudioInputStream getAudioInputStream() {
944 return audioInputStream;
945 }
946
947 public SamplingGraph getSamplingGraph() {
948 return samplingGraph;
949 }
950
951 public JButton getPlayB() {
952 return playB;
953 }
954
955 public JButton getCaptB() {
956 return captB;
957 }
958
959 public JButton getPausB() {
960 return pausB;
961 }
962
963 public JButton getLoadB() {
964 return loadB;
965 }
966
967 public JButton getAuB() {
968 return auB;
969 }
970
971 public JButton getAiffB() {
972 return aiffB;
973 }
974
975 public JButton getWaveB() {
976 return waveB;
977 }
978
979 public JTextField getTextField() {
980 return textField;
981 }
982
983 public String getFileName() {
984 return fileName;
985 }
986
987 public String getErrStr() {
988 return errStr;
989 }
990
991 public double getDuration() {
992 return duration;
993 }
994
995 public double getSeconds() {
996 return seconds;
997 }
998
999 public File getFile() {
1000 return file;
1001 }
1002
1003 public Vector getGraphicLineData() {
1004 return graphicLineData;
1005 }
1006 }
1007