/Users/lyon/j4p/src/sound/AudioBuffer.java
|
1 package sound;
2
3 import javax.sound.sampled.AudioFormat;
4 import javax.sound.sampled.AudioInputStream;
5 import javax.sound.sampled.AudioSystem;
6 import java.io.ByteArrayInputStream;
7 import java.io.ByteArrayOutputStream;
8 import java.io.IOException;
9
10 /********************************************************/
11
12 /**
13 * An AudioBuffer is a self-describing fragment of audio in memory.
14 * It can be read and written in a manner similar to
15 * java.io.ByteArrayInputStream and java.io.ByteArrayOutputStream.
16 * It knows how to transcode itself from one audio format to another.
17 * <p>
18 * GRJ - 11/5/02 - This code can probably be simplifed somewhat, but
19 * my initial goal was to break out this functionality. The goal
20 * was to make an interface that works. The implementation can be
21 * cleaned up in the next version.
22 *
23 */
24 public class AudioBuffer {
25 private AudioFormat format = null;
26 private byte[] audioByteArray = null;
27 private AudioInputStream inputStream = null;
28 private ByteArrayOutputStream outputStream = null;
29
30 /********************************************************/
31 /**
32 * Construct an empty AudioBuffer which will hold data of the
33 * specified format.
34 */
35 public AudioBuffer(AudioFormat format) {
36 this.format = format;
37 }
38
39 /********************************************************/
40 /**
41 * Construct an AudioBuffer containing audio from the supplied
42 * byte array.
43 */
44 public AudioBuffer(AudioFormat format, byte[] audioByteArray) {
45 this.format = format;
46 this.audioByteArray = audioByteArray;
47 }
48
49 /********************************************************/
50 /**
51 * Construct an AudioBuffer containing audio from the supplied
52 * AudioInputStream.
53 */
54 public AudioBuffer(AudioInputStream ais) {
55 try {
56 audioByteArray = new byte[ais.available()];
57 ais.mark(ais.available());
58 ais.read(audioByteArray, 0, ais.available());
59 format = ais.getFormat();
60 ais.reset();
61 } catch (IOException ioe) {
62 // what should I do here?
63 ioe.printStackTrace();
64 }
65 }
66
67 /********************************************************/
68 /**
69 * Get the AudioFormat.Encoding corresponding to the AudioBuffer's
70 * audio data.
71 */
72 public AudioFormat.Encoding getEncoding() {
73 return format.getEncoding();
74 }
75
76 /********************************************************/
77 /**
78 * Get the sample rate (samples per second) of the AudioBuffer's data.
79 */
80 public float getSampleRate() {
81 return format.getSampleRate();
82 }
83
84 /********************************************************/
85 /**
86 * Get the frame size (bytes per sample) of the AudioBuffer's data.
87 */
88 public int getFrameSize() {
89 return format.getFrameSize();
90 }
91
92 /********************************************************/
93 /**
94 * Get the audio format of the buffer's data as an AudioFormat object.
95 */
96 public AudioFormat getFormat() {
97 return format;
98 }
99
100 /********************************************************/
101 /**
102 * Obtain a byte array that contains the AudioBuffer's data.
103 */
104 public byte[] toByteArray() {
105 return audioByteArray;
106 }
107
108 /********************************************************/
109 /**
110 * Obtain an AudioInputStream that contains the AudioBuffer's data.
111 */
112 public AudioInputStream toAudioInputStream() {
113 inputStream = new AudioInputStream(
114 new ByteArrayInputStream(audioByteArray),
115 format,
116 audioByteArray.length / format.getFrameSize()
117 );
118 return inputStream;
119 }
120
121 /********************************************************/
122 /**
123 * Convert the encoding of the audio in the buffer to the
124 * specified encoding.
125 * <p>
126 * GRJ - 11/5/02 - This is inefficient code. See disclaimer above.
127 * <p>
128 * Also, there seems to be a bug in the implementation here (or in
129 * the transcoding version of AudioSystem.getAudioInputStream used by
130 * the implementation?). The available() method of AudioInputStream does
131 * not return a different length after the transcode if the number
132 * of bytes per sample changes. I had to do a workaround.
133 */
134 public void transcode(AudioFormat.Encoding destinationEncoding) {
135 if (destinationEncoding == null) {
136 return;
137 }
138
139 try {
140 AudioFormat formats[] = AudioSystem.getTargetFormats(destinationEncoding, format);
141
142 int inputByteLength = audioByteArray.length;
143 int outputByteLength = inputByteLength * formats[0].getFrameSize() / format.getFrameSize();
144
145 AudioInputStream ais = new AudioInputStream(
146 new ByteArrayInputStream(audioByteArray),
147 format,
148 inputByteLength / format.getFrameSize()
149 );
150
151 ais = AudioSystem.getAudioInputStream(formats[0], ais);
152
153 byte[] newByteArray = new byte[outputByteLength];
154 ais.read(newByteArray, 0, outputByteLength);
155 format = formats[0];
156 ais.close();
157 audioByteArray = newByteArray;
158 inputStream = null;
159 } catch (IOException ioe) {
160 // what should I do here?
161 ioe.printStackTrace();
162 }
163
164 }
165
166 /********************************************************/
167 /**
168 * Retrieve data from the buffer.
169 */
170 public int read(byte[] b, int off, int len) throws IOException {
171 if (inputStream == null) {
172 toAudioInputStream();
173 }
174 return inputStream.read(b, off, len);
175 }
176
177 /********************************************************/
178 /**
179 * Add data to the buffer.
180 */
181 public void write(byte[] b, int off, int len) {
182 if (outputStream == null) {
183 outputStream = new ByteArrayOutputStream();
184 }
185 outputStream.write(b, off, len);
186 audioByteArray = outputStream.toByteArray();
187 }
188 }