/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  }