/Users/lyon/j4p/src/sound/player/SoundCapture.java

1    package sound.player; 
2     
3    /** 
4     * Created by IntelliJ IDEA. 
5     * User: Douglas Lyon 
6     * Date: Dec 13, 2004 
7     * Time: 9:05:37 PM 
8     * Copyright DocJava, Inc. 
9     */ 
10   import java.io.*; 
11   import java.net.*; 
12   import java.util.Enumeration; 
13    
14   import javax.sound.sampled.*; 
15    
16   ////////////////////////////////////////////////////////////////////////// 
17   //// SoundCapture 
18   /** 
19      <h2>Overview</h2> 
20      A buffer supporting the capturing of audio samples from a file or 
21      from the computer's audio input port. This class supports the 
22      real-time capture of audio from the audio input port (mic or line-in) 
23      as well as the capture of audio from a sound file specified as 
24      a URL. Single channel 
25      (mono) and multichannel audio (stereo) are supported. This class, 
26      along with SoundPlayback, intends to provide an easy to use interface 
27      to Java Sound, Java's audio API. Java Sound supports the capture 
28      of audio data, but only at the byte level, which is audio format 
29      specific. This class, however, provides higher level support for the 
30      capture of double or integer valued samples from the computer's audio 
31      input port or any supported sound file type. This class is therefore 
32      useful when it one desires to capture audio samples in an audio format 
33      independent way. 
34      <p> 
35      Depending on available audio 
36      system resources, it may be possible to run an instance of this 
37      class and an instance of SoundPlayback concurrently. This allows 
38      for the concurrent capture, signal processing, and playback of audio data. 
39      <p> 
40      <h2>Usage</h2> 
41      Two constructors are provided. One constructor creates a sound capture 
42      object that captures from the line-in or microphone port. 
43      The operating system must be used 
44      to select between the microphone and line-in. This cannot be 
45      done using Java. If this 
46      constructor is used, there will be a small 
47      delay between the time that the audio enters the microphone or 
48      line-in and the time that the corresponding audio samples are 
49      available via getSamples() or getSamplesInt(). 
50      This latency can be adjusted by setting the <i>bufferSize</i> 
51      constructor parameter. Another constructor creates a sound capture 
52      object that captures audio from a sound file specified as a URL. 
53      <p> 
54      After calling the appropriate constructor, startCapture() 
55      must be called to initialize the audio system for capture. 
56      The getSamples() or getSamplesInt() method should then be repeatedly 
57      invoked to obtain audio data in the form of a multidimensional 
58      array of audio sample values. getSamples() will return audio 
59      sample values in the range [-1, 1]. getSamplesInt() will return 
60      audio samples in the range 
61      (-2^(bits_per_sample/2), 2^(bits_per_sample/2)), where 
62      bits_per_sample is the number of bits per sample. 
63      For the case where 
64      audio is captured from the mic or line-in, it is important to 
65      invoke getSamples() or getSamplesInt() often enough to prevent 
66      overflow of 
67      the internal audio buffer. The size of the internal buffer is 
68      set in the constructor. Note that it is possible (but probably 
69      not useful) to interleave calls to getSamples() and 
70      getSamplesInt(). 
71      Finally, after no more audio data is desired, stopCapture() 
72      should be called to free up audio system resources. 
73      <p> 
74      <h2>Security issues</h2> 
75      Applications have no restrictions on the 
76      capturing or playback of audio. Applets, however, may only capture 
77      audio from a file specified as a URL on the same machine as the 
78      one the applet was loaded from. Applet code is not allowed to 
79      read or write native files. The .java.policy file must be 
80      modified to grant applets more privileges. 
81      <p> 
82      Note: Requires Java 2 v1.3.0 or later. 
83    
84      @author Brian K. Vogel 
85      @version $Id: SoundCapture.java,v 1.38 2003/04/11 16:15:17 cxh Exp $ 
86      @since Ptolemy II 1.0 
87    
88   */ 
89    
90   public class SoundCapture { 
91    
92       /** Construct a sound capture object that captures audio from a computer's 
93        *  audio input port.  If this constructor is used, then it 
94        *  is important that getSamples() be 
95        *  invoked often enough to prevent overflow of the internal audio 
96        *  input buffer. Note the startCapture() must be called before the 
97        *  first invocation of getSamples(), otherwise getSamples() will 
98        *  throw an exception. 
99        *  @param sampleRate Sample rate in Hz. Must be in the range: 8000 
100       *   to 48000. 
101       *  @param sampleSizeInBits Number of bits per sample. Choices are 
102       *   8 or 16. 
103       *  @param channels Number of audio channels. 1 for mono, 2 for 
104       *   stereo. 
105       *  @param bufferSize Requested size of the internal audio input 
106       *   buffer in samples. This controls the latency. A lower bound 
107       *   on the latency is given by (<i>bufferSize</i> / <i>sampleRate</i>) 
108       *   seconds. Ideally, the 
109       *   smallest value that gives acceptable performance (no overflow) 
110       *   should be used. Typical values are about 1/10 th the sample 
111       *   rate. For example, at 44100 Hz sample rate, a typical buffer 
112       *   size value might be 4410. 
113       *  @param getSamplesSize Size of the array returned by 
114       *   getSamples(). For performance reasons, the size should 
115       *   be chosen smaller than <i>bufferSize</i>. Typical values 
116       *   are 1/2 to 1/16th of <i>bufferSize</i>. 
117       */ 
118      public SoundCapture(float sampleRate, int sampleSizeInBits, 
119              int channels, int bufferSize, 
120              int getSamplesSize) { 
121          _isAudioCaptureActive = false; 
122          // Set mode to real-time. 
123          this._isRealTime = true; 
124          this._sampleSizeInBits = sampleSizeInBits; 
125          this._sampleRate = sampleRate; 
126          this._channels = channels; 
127          this._bufferSize = bufferSize; 
128          this._productionRate = getSamplesSize; 
129      } 
130   
131      /** Construct a sound capture object that captures audio from a 
132       *  sound file specified as a URL. Note that it is still possible 
133       *  to capture audio from a file on the local file system. For 
134       *  example, to capture from a sound file located at 
135       *  "C:\someDir\someFile.wave", <i>pathName</i> 
136       *  should be set to "file:///C:/someDir/someFile.wave". 
137       *  <p> 
138       *  Note the startCapture() must be called before the 
139       *  first invocation of getSamples(), otherwise getSamples() will 
140       *  throw an exception. 
141       * 
142       *  @param pathName The name of the file as a URL. Valid sound file 
143       *   formats are WAVE (.wav), AIFF (.aif, .aiff), AU (.au). The file 
144       *   format is automatically determined from the file extension. 
145       *   If there is a problem reading the sound file, an IOException 
146       *   will be thrown in startCapture(). 
147       *  @param getSamplesSize The number of samples per channel 
148       *   returned by getSamples(). 
149       */ 
150      public SoundCapture(String pathName, 
151              int getSamplesSize) { 
152          _isAudioCaptureActive = false; 
153          // Set mode to "capture from file" (not real-time). 
154          this._isRealTime = false; 
155          this._pathName = pathName; 
156          this._productionRate = getSamplesSize; 
157      } 
158   
159      /////////////////////////////////////////////////////////////////// 
160      ///  Public Methods                                         /// 
161   
162   
163      /** Return the number of audio channels. This method will 
164       *  return the number of audio channels, regardless of 
165       *  which constructor was used. However, this method is 
166       *  really only useful when the constructor that causes 
167       *  audio to be captured from a file is used, since 
168       *  the number of channels is unknown until the file 
169       *  is opened. 
170       *  <p> 
171       *  This method should 
172       *  be called while audio capture is active, i.e., after 
173       *  startCapture() is called and before stopCapture() 
174       *  is called. 
175       * 
176       *  @return The number of audio channels. Return null if 
177       *   this method is called before startCapture(). 
178       * 
179       *  @exception IllegalStateException If this method is called 
180       *   before startCapture() is called or after stopCapture() 
181       *   is called. 
182       */ 
183      public int getChannels() throws IllegalStateException { 
184          if (_isAudioCaptureActive == true) { 
185              return _channels; 
186          } else { 
187              throw new IllegalStateException("SoundCapture: " + 
188                      "getChannels() was called while audio capture was" + 
189                      " inactive (startCapture() was never called)."); 
190          } 
191      } 
192   
193      /** Return the sampling rate in Hz. This method will 
194       *  return the sampling rate, regardless of 
195       *  which constructor was used. However, this method is 
196       *  really only useful when the constructor that causes 
197       *  audio to be captured from a file is used, since 
198       *  the sampling rate is unknown until the file 
199       *  is opened. 
200       *  <p> 
201       *  This method should 
202       *  be called while audio capture is active, i.e., after 
203       *  startCapture() is called and before stopCapture() 
204       *  is called. 
205       * 
206       *  @return The sample rate in Hz. Return null if 
207       *   this method is called before startCapture(). 
208       * 
209       *  @exception IllegalStateException If this method is called 
210       *   before startCapture() is called or after stopCapture() 
211       *   is called. 
212       */ 
213      public float getSampleRate() throws IllegalStateException { 
214          if (_isAudioCaptureActive == true) { 
215              return _sampleRate; 
216          } else { 
217              throw new IllegalStateException("SoundCapture: " + 
218                      "getSampleRate() was called while audio capture was" + 
219                      " inactive (startCapture() was never called)."); 
220          } 
221      } 
222   
223      /** Return an array of captured audio samples. This method 
224       *  should be repeatedly called to obtain audio data. 
225       *  The returned audio samples will have values in the range 
226       *  [-1, 1], regardless of the audio bit resolution (bits per 
227       *  sample). When 
228       *  capturing from the computer's audio input port (mic or 
229       *  line-in), this method should be called often enough to 
230       *  prevent overflow of the internal audio buffer. If 
231       *  overflow occurs, some audio data will be lost but no 
232       *  exception or other error condition will occur. If 
233       *  the audio data is not yet available, then this method 
234       *  will block until the data is available. When capturing 
235       *  from a sound file, it is not possible for overflow to 
236       *  occur. 
237       *  <p> 
238       *  The array size 
239       *  is set by the <i>getSamplesSize</i> parameter in the 
240       *  constructor. For the case where audio is captured from 
241       *  the computer's audio-in port (mic or line-in), this 
242       *  method should be called often enough to prevent overflow 
243       *  of the internal audio buffer, the size of which is set 
244       *  in the constructor. 
245       *  @return Two dimensional array of captured audio samples. 
246       *   Return null 
247       *  if end of audio file is reached. A null return value is 
248       *  only possible when capturing from a sound file. 
249       *  The first index 
250       *  represents the channel number (0 for first channel, 1 for 
251       *  second channel, etc.). The second index represents the 
252       *  sample index within a channel. For example, 
253       *  <i>returned array</i>[n][m] contains the (m+1)th sample 
254       *  of the (n+1)th channel. For each channel, n, the length of 
255       *  <i>returned array</i>[n] is equal to <i>getSamplesSize</i>. 
256       * 
257       *  @exception IOException If there is a problem capturing audio. 
258       *  @exception IllegalStateException If audio capture is currently 
259       *  inactive. That is, If startCapture() has not yet been called 
260       *  or if stopCapture() has already been called. 
261       */ 
262      public double[][] getSamples() throws IOException, 
263              IllegalStateException { 
264          if (_isAudioCaptureActive == true) { 
265              int numBytesRead; 
266              if (_isRealTime == true) { 
267                  // Real-time capture. 
268                  numBytesRead = _targetLine.read(_data, 0, 
269                          _productionRate*_frameSizeInBytes); 
270   
271              } else { 
272                  // Capture audio from file. 
273                  numBytesRead = 
274                      _properFormatAudioInputStream.read(_data); 
275              } 
276              if (numBytesRead == _data.length) { 
277                  // Convert byte array to double array. 
278                  _audioInDoubleArray = 
279                      _byteArrayToDoubleArray(_data, 
280                              _bytesPerSample, 
281                              _channels); 
282                  return _audioInDoubleArray; 
283              } else if (numBytesRead != _data.length) { 
284                  // Read fewer samples than productionRate many samples. 
285                  // FIXME: There appears to be a java sound bug that 
286                  // causes AudioInputStream.read(array) to sometimes 
287                  // return fewer bytes than requested, even though 
288                  // the end of the file has not yet been reached. 
289                  _audioInDoubleArray = 
290                      _byteArrayToDoubleArray(_data, 
291                              _bytesPerSample, 
292                              _channels); 
293                  return _audioInDoubleArray; 
294              } else if (numBytesRead == -1) { 
295                  // Ran out of samples to play. This generally means 
296                  // that the end of the sound file has been reached. 
297                  return null; 
298              } 
299              return null; 
300          } else { 
301              throw new IllegalStateException("SoundCapture: " + 
302                      "getSamples() was called while audio capture was" + 
303                      " inactive (startCapture() was never called or " + 
304                      "stopCapture has already been called)."); 
305          } 
306      } 
307   
308      /** Return an array of captured audio samples. This method 
309       *  should be repeatedly called to obtain audio data. This 
310       *  method requires less computation than getSamples(), 
311       *  since no conversion to doubles is performed. Therefore, 
312       *  the use of this method is recommended when integer 
313       *  valued audio samples are sufficient. The 
314       *  returned audio samples will have values in the range 
315       *  (-2^(bits_per_sample/2), 2^(bits_per_sample/2)). The 
316       *  range of sample values returned is therefore dependent 
317       *  on the bit resolution of the audio data. If this is not 
318       *  desired, then use getSamples() instead. 
319       *  <p> 
320       *  When capturing from the computer's audio input port (mic or 
321       *  line-in), this method should be called often enough to 
322       *  prevent overflow of the internal audio buffer. If 
323       *  overflow occurs, some audio data will be lost but no 
324       *  exception or other error condition will occur. If 
325       *  the audio data is not yet available, then this method 
326       *  will block until the data is available. When capturing 
327       *  from a sound file, it is not possible for overflow to 
328       *  occur. 
329       *  <p> The  array size 
330       *  is set by the <i>getSamplesSize</i> parameter in the 
331       *  constructor. For the case where audio is captured from 
332       *  the computer's audio-in port (mic or line-in), this 
333       *  method should be called often enough to prevent overflow 
334       *  of the internal audio buffer, the size of which is set 
335       *  in the constructor. 
336       *  @return Two dimensional array of captured audio samples. 
337       *   Return null 
338       *  if end of audio file is reached A null return value is 
339       *  only possible when capturing from a sound file. 
340       *  The first index 
341       *  represents the channel number (0 for first channel, 1 for 
342       *  second channel, etc.). The second index represents the 
343       *  sample index within a channel. For example, 
344       *  <i>returned array</i>[n][m] contains the (m+1)th sample 
345       *  of the (n+1)th channel. For each channel, n, the length of 
346       *  <i>returned array</i>[n] is equal to <i>getSamplesSize</i>. 
347       * 
348       *  @exception IOException If there is a problem capturing audio. 
349       *  @exception IllegalStateException If audio capture is currently 
350       *  inactive. That is, If startCapture() has not yet been called 
351       *  or if stopCapture() has already been called. 
352       */ 
353      public int[][] getSamplesInt() throws IOException, 
354              IllegalStateException { 
355          if (_isAudioCaptureActive == true) { 
356              int numBytesRead; 
357              if (_isRealTime == true) { 
358                  // Real-time capture. 
359                  numBytesRead = _targetLine.read(_data, 0, 
360                          _productionRate*_frameSizeInBytes); 
361   
362              } else { 
363                  // Capture audio from file. 
364                  numBytesRead = 
365                      _properFormatAudioInputStream.read(_data); 
366              } 
367              if (numBytesRead == _data.length) { 
368                  // Convert byte array to double array. 
369                  _audioInIntArray = 
370                      _byteArrayToIntArray(_data, 
371                              _bytesPerSample, 
372                              _channels); 
373                  return _audioInIntArray; 
374              } else if (numBytesRead != _data.length) { 
375                  // Read fewer samples than productionRate many samples. 
376   
377                  // FIXME: Output the samples that were read + zeros? 
378                  return null; 
379              } else if (numBytesRead == -1) { 
380                  // Ran out of samples to play. This generally means 
381                  // that the end of the sound file has been reached. 
382                  return null; 
383              } 
384              return null; 
385          } else { 
386              throw new IllegalStateException("SoundCapture: " + 
387                      "getSamples() was called while audio capture was" + 
388                      " inactive (startCapture() was never called or " + 
389                      "stopCapture has already been called)."); 
390          } 
391      } 
392   
393      /** Begin capturing audio. This method must be invoked prior 
394       *  to the first invocation of getSamples(). If this is not 
395       *  done, then getSamples() will throw an exception when 
396       *  it is invoked. It is safe 
397       *  to call getSamples() immediately after this method returns. 
398       *  This method must not be called more than 
399       *  once between invocations of stopCapture(). Calling 
400       *  this method more than once between invocations of 
401       *  stopCapture() will cause this method to throw an exception. 
402       * 
403       *  @exception IOException If there is a problem setting up 
404       *  the system for audio capture. This will occur if the 
405       *  a URL cannot be opened or if the audio in port cannot 
406       *  be accessed. 
407       *  @exception IllegalStateException If this method is called 
408       *  more than once between invocations of stopCapture(). 
409       */ 
410      public void startCapture() throws IOException, 
411              IllegalStateException { 
412          if (_isAudioCaptureActive == false) { 
413              // FIXME: check and throw Exceptions 
414              if (_isRealTime == true) { 
415                  _startCaptureRealTime(); 
416              } else { 
417                  _startCaptureFromFile(); 
418              } 
419              _isAudioCaptureActive = true; 
420          } else { 
421              throw new IllegalStateException("SoundCapture: " + 
422                      "startCapture() was called while audio capture was" + 
423                      " already active (startCapture() was called " + 
424                      "more than once between invocations of stopCapture())."); 
425          } 
426      } 
427   
428      /** Stop capturing audio. This method should be called when 
429       *  no more calls to getSamples(). are required, so 
430       *  that the system resources involved in the audio capture 
431       *  may be freed. 
432       * 
433       *  @exception IOException If there is a problem closing the 
434       *  audio resources. 
435       */ 
436      public void stopCapture() throws IOException { 
437          if (_isAudioCaptureActive == true) { 
438              // Free up audio system resources. 
439              // For capture from file: 
440              if (_audioInputStream != null) { 
441                  _audioInputStream.close(); 
442   
443                  // FIXME : is this correct? 
444                  _audioInputStream = null; 
445              } 
446              if (_properFormatAudioInputStream != null) { 
447                  _properFormatAudioInputStream.close(); 
448   
449                  // FIXME : is this correct? 
450                  _properFormatAudioInputStream = null; 
451              } 
452              // For real-time capture: 
453              if (_targetLine != null) { 
454   
455                  if (_targetLine.isOpen() == true) { 
456                      _targetLine.stop(); 
457                      _targetLine.close(); 
458                      _targetLine = null; 
459                  } 
460              } 
461          } 
462          _isAudioCaptureActive = false; 
463      } 
464   
465      /** Return the number of bits per audio sample. This method will 
466       *  return the number of bits per audio sample, regardless of 
467       *  which constructor was used. However, this method is 
468       *  really only useful when the constructor that causes 
469       *  audio to be captured from a file is used, since 
470       *  the number of bits per audio sample is unknown until the file 
471       *  is opened. 
472       *  <p> 
473       *  This method must 
474       *  be called while audio capture is active, i.e., after 
475       *  startCapture() is called and before stopCapture() 
476       *  is called, or else an exception will be thrown. 
477       * 
478       * @return The sample size in bits. Return null if 
479       *  this method is called before startCapture(). 
480       * 
481       * @exception IllegalStateException If this method is called 
482       *  before startCapture() is called or after stopCapture() 
483       *  is called. 
484       */ 
485      public int getSampleSizeInBits() throws IllegalStateException { 
486          if (_isAudioCaptureActive == true) { 
487              return _sampleSizeInBits; 
488          } else { 
489              throw new IllegalStateException("SoundCapture: " + 
490                      "getSampleSizeInBits() was called while audio capture was" + 
491                      " inactive (startCapture() was never called)."); 
492          } 
493      } 
494   
495      /////////////////////////////////////////////////////////////////// 
496      ////                         private methods                   //// 
497   
498      private void _startCaptureRealTime() throws IOException { 
499   
500          int frameSizeInBits = _sampleSizeInBits; 
501          double frameRate = _sampleRate; 
502          boolean signed = true; 
503          boolean bigEndian = true; 
504   
505          AudioFormat format = new AudioFormat(_sampleRate, 
506                  _sampleSizeInBits, 
507                  _channels, signed, bigEndian); 
508   
509          _frameSizeInBytes = format.getFrameSize(); 
510   
511          DataLine.Info targetInfo = new DataLine.Info(TargetDataLine.class, 
512                  format, AudioSystem.NOT_SPECIFIED); 
513   
514          // The following works under Windows Java 1.3.0 RC2 but 
515          // not under Tritonus under Linux, so comment out. 
516          //if (!AudioSystem.isLineSupported(targetInfo)) { 
517          //    // FIXME: throw exception here. 
518          //    System.out.println("Line matching " + targetInfo + 
519          //            " not supported."); 
520          //    return; 
521          //} 
522   
523          try { 
524              _targetLine = (TargetDataLine) AudioSystem.getLine(targetInfo); 
525              // Note: 2nd parameter is the buffer size (in bytes). 
526              // Larger values increase latency but may be required if 
527              // garbage collection, etc. is an issue. 
528              _targetLine.open(format, _bufferSize*_frameSizeInBytes); 
529          } catch (LineUnavailableException ex) { 
530              throw new IOException("Unable to open the line for " + 
531                      "real-time audio capture: " + ex); 
532          } 
533   
534          int targetBufferLengthInBytes = _productionRate * 
535              _frameSizeInBytes; 
536   
537          // The following works under Windows Java 1.3.0 RC2 but 
538          // not under Tritonus under Linux, so comment out. 
539          //if (!AudioSystem.isLineSupported(sourceInfo)) { 
540          //    //FIXME: handle this correctly. 
541          //    System.err.println("Line matching " + sourceInfo + 
542          //            " not supported."); 
543          //    return; 
544          //} 
545   
546          // Array of audio samples in byte format. 
547          _data = new byte[_productionRate*_frameSizeInBytes]; 
548   
549          _bytesPerSample = _sampleSizeInBits/8; 
550   
551          // Start the target data line 
552          _targetLine.start(); 
553   
554      } 
555   
556   
557      /* Perform necessary initialization to capture from a sound 
558       * file. The sound file is specified as a URL. 
559       */ 
560      private void _startCaptureFromFile() throws IOException { 
561          // Load audio from a URL. 
562          // Create a URL corresponding to the sound file location. 
563          URL soundURL = 
564              new URL(_pathName); 
565   
566          if (soundURL != null) { 
567              try { 
568                  _audioInputStream = 
569                      AudioSystem.getAudioInputStream(soundURL); 
570              } catch (UnsupportedAudioFileException e) { 
571                  throw new IOException("Unsupported AudioFile :" + 
572                          e); 
573              } 
574          } 
575   
576          // make sure we have something to play 
577          if (_audioInputStream == null) { 
578              throw new IOException("No loaded audio to play back"); 
579          } 
580   
581          // FIXME: is this correct? 
582          //_audioInputStream.reset(); 
583   
584          AudioFormat origFormat = _audioInputStream.getFormat(); 
585          // Now convert to PCM_SIGNED_BIG_ENDIAN so that can get double 
586          // representation of samples. 
587          float sampleRate = origFormat.getSampleRate(); 
588   
589          _sampleSizeInBits = origFormat.getSampleSizeInBits(); 
590          _bytesPerSample = _sampleSizeInBits/8; 
591   
592          _channels = origFormat.getChannels(); 
593          boolean signed = true; 
594          boolean bigEndian = true; 
595          AudioFormat format = new AudioFormat(sampleRate, 
596                  _sampleSizeInBits, _channels, 
597                  signed, bigEndian); 
598          _properFormatAudioInputStream = 
599              AudioSystem.getAudioInputStream(format, _audioInputStream); 
600   
601          _frameSizeInBytes = format.getFrameSize(); 
602   
603          // FIXME: is this correct? 
604          //_properFormatAudioInputStream.reset(); 
605   
606          // Array of audio samples in byte format. 
607          _data = new byte[_productionRate*_frameSizeInBytes]; 
608   
609          // Initialize the index to the first sample of the sound file. 
610          _index = 0; 
611      } 
612   
613      /* Convert a byte array of audio samples in linear signed pcm big endian 
614       * format into a double array of audio samples (-1, 1) range. 
615       * @param byteArray  The linear signed pcm big endian byte array 
616       * formatted array representation of audio data. 
617       * @param bytesPerSample Number of bytes per sample. Supported 
618       * bytes per sample by this method are 8, 16, 24, 32. 
619       * @param channels Number of audio channels. 1 for mono, 2 for 
620       * stereo. 
621       * @return Two dimensional array holding audio samples. 
622       * For each channel, m, doubleArray[m] is a single dimensional 
623       * array containing samples for channel m. 
624       */ 
625      private double[][] _byteArrayToDoubleArray(byte[] byteArray, 
626              int bytesPerSample, 
627              int channels) { 
628          int lengthInSamples = byteArray.length / (bytesPerSample*channels); 
629          // Check if we need to reallocate. 
630          if ((channels != _doubleArray.length) || 
631                  (lengthInSamples != _doubleArray[0].length)) { 
632              // Reallocate 
633              _doubleArray = new double[channels][lengthInSamples]; 
634          } 
635          //double maxSampleReciprocal = 1/(Math.pow(2, 8 * bytesPerSample - 1)); 
636          // Could use above line, but hopefully, code below will 
637          // be faster. 
638          double maxSampleReciprocal; 
639          if (bytesPerSample == 2) { 
640              // 1 / 32768 
641              maxSampleReciprocal = 3.0517578125e-5; 
642          } else if (bytesPerSample == 1) {            // 1 / 128 
643              maxSampleReciprocal = 7.8125e-3; 
644          } else if (bytesPerSample == 3) { 
645              // 1 / 8388608 
646              maxSampleReciprocal = 1.1920928955e07; 
647          } else if (bytesPerSample == 4) { 
648              // 1 / 147483648e9 
649              maxSampleReciprocal = 4.655661287308e-10; 
650          } else { 
651              // Should not happen. 
652              maxSampleReciprocal = 0; 
653          } 
654   
655          // Check if we need to reallocate. 
656          // FIXME: This test is really not needed since bytesPerSample 
657          // is set in the constructor. It should never change. 
658          if (bytesPerSample != _b.length) { 
659              _b = new byte[bytesPerSample]; 
660          } 
661   
662          for (int currSamp = 0; currSamp < lengthInSamples; currSamp++) { 
663   
664              // For each channel, 
665              for (int currChannel = 0; currChannel < channels; currChannel++) { 
666                  for (int i = 0; i < bytesPerSample; i += 1) { 
667                      // Assume we are dealing with big endian. 
668                      _b[i] = byteArray[currSamp*bytesPerSample*channels + 
669                              bytesPerSample*currChannel + i]; 
670                  } 
671                  int result = (_b[0] >> 7) ; 
672                  for (int i = 0; i < bytesPerSample; i += 1) 
673                      result = (result << 8) + (_b[i] & 0xff); 
674                  _doubleArray[currChannel][currSamp] = 
675                      ((double) result*maxSampleReciprocal); 
676              } 
677          } 
678          return _doubleArray; 
679      } 
680   
681      /* Convert a byte array of audio samples in linear signed pcm big endian 
682       * format into a (signed) int array of audio samples. The range 
683       * of the returned samples is approximately 
684       * (-2^(bits_per_sample/2), 2^(bits_per_sample/2)). 
685       * @param byteArray  The linear signed pcm big endian byte array 
686       * formatted array representation of audio data. 
687       * @param bytesPerSample Number of bytes per sample. Supported 
688       * bytes per sample by this method are 8, 16, 24, 32. 
689       * @param channels Number of audio channels. 1 for mono, 2 for 
690       * stereo. 
691       * @return Two dimensional array holding audio samples. 
692       * For each channel, m, intArray[m] is a single dimensional 
693       * array containing samples for channel m. 
694       */ 
695      private int[][] _byteArrayToIntArray(byte[] byteArray, 
696              int bytesPerSample, 
697              int channels) { 
698          int lengthInSamples = byteArray.length / (bytesPerSample*channels); 
699          // Check if we need to reallocate. 
700          if ((channels != _doubleArray.length) || 
701                  (lengthInSamples != _doubleArray[0].length)) { 
702              // Reallocate 
703              _intArray = new int[channels][lengthInSamples]; 
704          } 
705          // Check if we need to reallocate. 
706          // FIXME: This test is really not needed since bytesPerSample 
707          // is set in the constructor. It should never change. 
708          if (bytesPerSample != _b.length) { 
709              _b = new byte[bytesPerSample]; 
710          } 
711          for (int currSamp = 0; currSamp < lengthInSamples; currSamp++) { 
712   
713              // For each channel, 
714              for (int currChannel = 0; currChannel < channels; currChannel++) { 
715                  for (int i = 0; i < bytesPerSample; i += 1) { 
716                      // Assume we are dealing with big endian. 
717                      _b[i] = byteArray[currSamp*bytesPerSample*channels + 
718                              bytesPerSample*currChannel + i]; 
719                  } 
720                  int result = (_b[0] >> 7) ; 
721                  for (int i = 0; i < bytesPerSample; i += 1) 
722                      result = (result << 8) + (_b[i] & 0xff); 
723                  _intArray[currChannel][currSamp] = result; 
724              } 
725          } 
726          return _intArray; 
727      } 
728   
729   
730      /////////////////////////////////////////////////////////////////// 
731      ////                         private variables                 //// 
732   
733      private AudioInputStream  _properFormatAudioInputStream; 
734      private AudioInputStream _audioInputStream; 
735      private int _productionRate; 
736      // Array of audio samples in double format. 
737      private double[][] _audioInDoubleArray; 
738      // Array of audio samples in int format. 
739      private int[][] _audioInIntArray; 
740      // Array of audio samples in byte format. 
741      private byte[] _data; 
742      private int _index; 
743      private int _frameSizeInBytes; 
744      private boolean _isRealTime; 
745      private String _pathName; 
746      private int _sampleSizeInBits; 
747      private float _sampleRate; 
748      private int _channels; 
749      private int _bufferSize; 
750      private TargetDataLine _targetLine; 
751      private int _bytesPerSample; 
752      private boolean _isAudioCaptureActive; 
753      private byte[] _b = new byte[1]; 
754      private double[][] _doubleArray = new double[1][1]; 
755      private int[][] _intArray = new int[1][1]; 
756  } 
757