001: /**********************************************************************************
002: * $URL$
003: * $Id$
004: ***********************************************************************************
005: *
006: * Copyright (c) 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the"License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.tool.assessment.audio;
021:
022: import java.text.AttributedCharacterIterator;
023: import java.text.AttributedString;
024: import java.util.Locale;
025: import java.util.ResourceBundle;
026: import java.util.Vector;
027: import javax.sound.sampled.AudioFormat;
028: import javax.sound.sampled.AudioInputStream;
029: import java.awt.BasicStroke;
030: import java.awt.BorderLayout;
031: import java.awt.Color;
032: import java.awt.Dimension;
033: import java.awt.Font;
034: import java.awt.Graphics;
035: import java.awt.Graphics2D;
036: import java.awt.font.FontRenderContext;
037: import java.awt.font.LineBreakMeasurer;
038: import java.awt.font.TextAttribute;
039: import java.awt.font.TextLayout;
040: import java.awt.geom.Line2D;
041: import javax.swing.JPanel;
042: import java.awt.LayoutManager;
043:
044: /**
045: * Render a WaveForm.
046: */
047: public class AudioSampleGraphPanel extends JPanel {
048: static ResourceBundle res = AudioUtil.getInstance()
049: .getResourceBundle();
050:
051: static ColorModel colorModel = new ColorModel();
052:
053: private static final Font font10 = new Font("serif", Font.PLAIN, 10);
054: private static final Font font12 = new Font("serif", Font.PLAIN, 12);
055: private static final Color graphColor = colorModel
056: .getColor("graphColor");//new Color(0, 180, 20);
057: private static final Color currentPositionColor = colorModel
058: .getColor("graphCurrentPositionColor");// Color(64, 200, 20);
059: private static final Color backgroundColor = colorModel
060: .getColor("graphBackgroundColor");//new Color(0, 128, 20);
061: private static final Color gridColor = colorModel
062: .getColor("graphGridColor");// new Color(0, 140, 20);
063:
064: public AudioSampleGraphPanel() {
065: setBackground(backgroundColor);
066: }
067:
068: public void reportGraphStatus(String msg) {
069: System.out.println("Status: " + msg);
070: }
071:
072: public void createWaveForm(byte[] audioBytes, Vector lines,
073: AudioInputStream audioInputStream) {
074:
075: lines.removeAllElements(); // clear the old vector
076:
077: AudioFormat format = audioInputStream.getFormat();
078: if (audioBytes == null) {
079: try {
080: audioBytes = new byte[(int) (audioInputStream
081: .getFrameLength() * format.getFrameSize())];
082: audioInputStream.read(audioBytes);
083: } catch (Exception ex) {
084: reportGraphStatus(ex.toString());
085: return;
086: }
087: }
088:
089: Dimension d = getSize();
090: int w = d.width;
091: int h = d.height - 15;
092: int[] audioData = null;
093: if (format.getSampleSizeInBits() == 16) {
094: int nlengthInSamples = audioBytes.length / 2;
095: audioData = new int[nlengthInSamples];
096: if (format.isBigEndian()) {
097: for (int i = 0; i < nlengthInSamples; i++) {
098: /* First byte is MSB (high order) */
099: int MSB = (int) audioBytes[2 * i];
100: /* Second byte is LSB (low order) */
101: int LSB = (int) audioBytes[2 * i + 1];
102: audioData[i] = MSB << 8 | (255 & LSB);
103: }
104: } else {
105: for (int i = 0; i < nlengthInSamples; i++) {
106: /* First byte is LSB (low order) */
107: int LSB = (int) audioBytes[2 * i];
108: /* Second byte is MSB (high order) */
109: int MSB = (int) audioBytes[2 * i + 1];
110: audioData[i] = MSB << 8 | (255 & LSB);
111: }
112: }
113: } else if (format.getSampleSizeInBits() == 8) {
114: int nlengthInSamples = audioBytes.length;
115: audioData = new int[nlengthInSamples];
116: if (format.getEncoding().toString().startsWith(
117: res.getString("PCM_SIGN"))) {
118: for (int i = 0; i < audioBytes.length; i++) {
119: audioData[i] = audioBytes[i];
120: }
121: } else {
122: for (int i = 0; i < audioBytes.length; i++) {
123: audioData[i] = audioBytes[i] - 128;
124: }
125: }
126: }
127:
128: int frames_per_pixel = audioBytes.length
129: / format.getFrameSize() / w;
130: byte my_byte = 0;
131: double y_last = 0;
132: int numChannels = format.getChannels();
133: for (double x = 0; x < w && audioData != null; x++) {
134: int idx = (int) (frames_per_pixel * numChannels * x);
135: if (format.getSampleSizeInBits() == 8) {
136: my_byte = (byte) audioData[idx];
137: } else {
138: my_byte = (byte) (128 * audioData[idx] / 32768);
139: }
140: double y_new = (double) (h * (128 - my_byte) / 256);
141: lines.add(new Line2D.Double(x, y_last, x, y_new));
142: y_last = y_new;
143: }
144:
145: repaint();
146: }
147:
148: public void paintData(Graphics g, AudioSamplingData data) {
149: Vector lines;
150: AudioInputStream audioInputStream = data.getAudioInputStream();
151: String errStr;
152: Runnable capture;
153: Thread captureThread;
154: double seconds;
155: String fileName;
156: double duration;
157: double maxSeconds;
158:
159: lines = data.getLine();
160: errStr = data.getErrStr();
161: capture = data.getCapture();
162: captureThread = data.getCaptureThread();
163: seconds = data.getSeconds();
164: fileName = data.getFileName();
165: duration = data.getDuration();
166: maxSeconds = data.getMaxSeconds();
167: //System.out.println("*** seconds="+seconds);
168: //System.out.println("*** duration="+duration);
169:
170: Dimension d = getSize();
171: int w = d.width;
172: int h = d.height;
173: int INFOPAD = 15;
174:
175: Graphics2D g2 = (Graphics2D) g;
176: g2.setBackground(getBackground());
177: g2.clearRect(0, 0, w, h);
178: g2.setColor(colorModel.getColor("darkColor"));
179: g2.fillRect(0, h - INFOPAD, w, INFOPAD);
180:
181: int gridHeight = h - INFOPAD - 2;
182: drawGrid(g2, w, gridHeight);
183:
184: if (errStr != null) {
185: drawErrorText(errStr, w, g2);
186: } else if (captureThread != null) {
187: if (seconds > maxSeconds)
188: drawLengthText(maxSeconds, h, g2);
189: else
190: drawLengthText(seconds, h, g2);
191: } else {
192: if (duration > maxSeconds)
193: drawFileLengthText(seconds, fileName, maxSeconds, h, g2);
194: else
195: drawFileLengthText(seconds, fileName, duration, h, g2);
196:
197: if (audioInputStream != null) {
198: drawSamplingGraph(lines, g2);
199:
200: if (seconds != 0) {
201: drawCurrentPosition(seconds, duration, w, h,
202: INFOPAD, g2);
203: }
204: }
205: }
206: }
207:
208: private void drawGrid(Graphics2D g2, int w, int h) {
209: g2.setColor(gridColor);
210: for (int x = 0; x < w; x += 10) {
211: g2.draw(new Line2D.Double(x, 0, x, h));
212: }
213: for (int y = 0; y < h; y += 10) {
214: g2.draw(new Line2D.Double(0, y, w, y));
215: }
216: }
217:
218: private void drawCurrentPosition(double seconds, double duration,
219: int w, int h, int INFOPAD, Graphics2D g2) {
220: double loc = seconds / duration * w;
221: g2.setColor(currentPositionColor);
222: g2.setStroke(new BasicStroke(3));
223: g2.draw(new Line2D.Double(loc, 0, loc, h - INFOPAD - 2));
224: }
225:
226: private void drawSamplingGraph(Vector lines, Graphics2D g2) {
227: g2.setColor(graphColor);
228: for (int i = 1; i < lines.size(); i++) {
229: g2.draw((Line2D) lines.get(i));
230: }
231: }
232:
233: private void drawFileLengthText(double seconds, String fileName,
234: double duration, int h, Graphics2D g2) {
235: g2.setColor(graphColor);
236: g2.setFont(font12);
237: g2.drawString(res.getString("Length_1")
238: + String.valueOf(duration), 3, h - 4);
239: /*
240: g2.drawString(res.getString("File_") + fileName + " " +
241: res.getString("Length_1") +
242: String.valueOf(duration) + " " + res.getString("Position_") +
243: String.valueOf(seconds), 3, h - 4);
244: */
245: }
246:
247: private void drawLengthText(double seconds, int h, Graphics2D g2) {
248: g2.setColor(graphColor);
249: g2.setFont(font12);
250: g2.drawString(res.getString("Length_")
251: + String.valueOf(seconds), 3, h - 4);
252: }
253:
254: private void drawErrorText(String errStr, int w, Graphics2D g2) {
255: g2.setColor(colorModel.getColor("alertColor"));
256: g2.setFont(new Font(res.getString("g2_Font"), Font.BOLD, 20));
257: g2.drawString(res.getString("ERROR"), 5, 20);
258: AttributedString as = new AttributedString(errStr);
259: as.addAttribute(TextAttribute.FONT, font12, 0, errStr.length());
260: AttributedCharacterIterator aci = as.getIterator();
261: FontRenderContext frc = g2.getFontRenderContext();
262: LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
263: float x = 5, y = 25;
264: lbm.setPosition(0);
265: while (lbm.getPosition() < errStr.length()) {
266: TextLayout tl = lbm.nextLayout(w - x - 5);
267: if (!tl.isLeftToRight()) {
268: x = w - tl.getAdvance();
269: }
270: tl.draw(g2, x, y += tl.getAscent());
271: y += tl.getDescent() + tl.getLeading();
272: }
273: }
274:
275: } // End class SamplingGraph
|