source: trunk/src_apollo/org/apollo/gui/PeakTroughWaveFormRenderer.java@ 315

Last change on this file since 315 was 315, checked in by bjn8, 16 years ago

Apollo spin-off added

File size: 4.4 KB
Line 
1package org.apollo.gui;
2
3import javax.sound.sampled.AudioFormat;
4
5import org.apollo.audio.SampledAudioManager;
6
7/**
8 * A WaveFormRenderer where the peaks and troughs are always chosen for every chunk of aggregated frames.
9 *
10 * @author Brook Novak
11 *
12 */
13public class PeakTroughWaveFormRenderer implements WaveFormRenderer {
14
15 private static final int DEFAULT_PEAK_TOLERANCE = 20;
16
17 private int sampleSize;
18 private boolean isBigEndian;
19 private boolean isSigned;
20
21 // Alternate
22 private boolean lastSampleHigh = false;
23
24 /** When frames becomes more aggregated - the selected peaks are alternated evenly
25 * with a given tolerance*/
26 private int peakTolerance;
27
28 /**
29 * Constructor.
30 *
31 * @param audioFormat
32 * The format of the audio bytes to be rendered.
33 *
34 * @throws NullPointerException
35 * If audio format is null.
36 *
37 * @throws IllegalArgumentException
38 * If audioformat is not supported. See SampledAudioManager.isFormatSupportedForPlayback
39 */
40 public PeakTroughWaveFormRenderer(AudioFormat audioFormat) {
41 if (audioFormat == null) throw new NullPointerException("audioFormat");
42
43 if (!SampledAudioManager.getInstance().isFormatSupportedForPlayback(audioFormat))
44 throw new IllegalArgumentException();
45
46 sampleSize = audioFormat.getSampleSizeInBits();
47 isSigned = audioFormat.getEncoding().toString().startsWith("PCM_SIGN");
48 isBigEndian = audioFormat.isBigEndian();
49
50 peakTolerance = DEFAULT_PEAK_TOLERANCE * audioFormat.getFrameSize();
51 }
52
53 /**
54 * {@inheritDoc}
55 */
56 public float[] getSampleAmplitudes(byte[] audioBytes, int startFrame, int frameLength, int aggregationSize) {
57 assert(audioBytes != null);
58 assert(startFrame >= 0);
59 assert((startFrame + frameLength) <= (audioBytes.length / (sampleSize / 8)));
60
61 float[] amplitudes = new float[frameLength / aggregationSize];
62
63 if (sampleSize == 16) {
64
65 for (int i = 0; i < amplitudes.length; i++) {
66
67 int max = 0, absmax = -1, sample, abssample; // could use short, but int avoid casting everywhere
68
69 int startFrameIndex = (startFrame + (i * aggregationSize)) << 1;
70 int endFrameIndex = startFrameIndex + (aggregationSize << 1);
71
72 for (int k = startFrameIndex; k < endFrameIndex; k+=2) {
73
74 int lsb, msb;
75
76 if (isBigEndian) {
77
78 // First byte is MSB (high order)
79 msb = (int)audioBytes[k];
80
81 // Second byte is LSB (low order)
82 lsb = (int)audioBytes[k + 1];
83
84 } else {
85 // First byte is LSB (low order)
86 lsb = (int)audioBytes[k];
87
88 // Second byte is MSB (high order)
89 msb = (int)audioBytes[k + 1];
90 }
91
92 sample = (msb << 0x8) | (0xFF & lsb);
93
94 abssample = Math.abs(sample);
95
96 if (lastSampleHigh && sample < 0) {
97 abssample += peakTolerance;
98 } else if (!lastSampleHigh && sample > 0) {
99 abssample += peakTolerance;
100 }
101
102 if (abssample > absmax) {
103 max = sample;
104 absmax = abssample;
105 }
106
107 }
108
109 lastSampleHigh = max > 0;
110
111 amplitudes[i] = ((float)max) / 32768.0f;
112
113 }
114
115 } else if (sampleSize == 8) {
116
117 if (isSigned) {
118
119 // Find the peak within the block of aggregated frames
120 for (int i = 0; i < amplitudes.length; i++) {
121
122 byte max = 0, absmax = -1, sample, abssample;
123
124 int startFrameIndex = startFrame + (i * aggregationSize);
125 int endFrameIndex = startFrameIndex + aggregationSize;
126
127 for (int k = startFrameIndex; k < endFrameIndex; k++) {
128
129 sample = audioBytes[k];
130 abssample = (sample < 0) ? (byte)(sample * -1) : sample;
131
132 if (abssample > absmax) {
133 max = sample;
134 absmax = abssample;
135 }
136 }
137
138 amplitudes[i] = ((float)max) / 128.0f;
139
140 }
141
142 } else { // unsigned
143
144 // Find the peak within the block of aggregated frames
145 for (int i = 0; i < amplitudes.length; i++) {
146
147 int max = 0, absmax = -1, sample, abssample; // could use short, but int avoid casting everywhere
148
149 int startFrameIndex = startFrame + (i * aggregationSize);
150 int endFrameIndex = startFrameIndex + aggregationSize;
151
152 for (int k = startFrameIndex; k < endFrameIndex; k++) {
153
154 sample = (audioBytes[k] & 0xFF) - 128;
155 abssample = Math.abs(sample);
156
157 if (abssample > absmax) {
158 max = sample;
159 absmax = abssample;
160 }
161 }
162
163 amplitudes[i] = ((float)max) / 128.0f;
164
165 }
166
167 }
168
169 }
170
171 return amplitudes;
172 }
173
174}
Note: See TracBrowser for help on using the repository browser.