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