001/* A buffer supporting the capturing of audio samples from a file or
002 from the computer's audio input port.
003
004 Copyright (c) 2000-2015 The Regents of the University of California.
005 All rights reserved.
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the above
009 copyright notice and the following two paragraphs appear in all copies
010 of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION_2
026 COPYRIGHTENDKEY
027
028 */
029package ptolemy.media.javasound;
030
031import java.io.IOException;
032import java.net.URL;
033
034import javax.sound.sampled.AudioFormat;
035import javax.sound.sampled.AudioInputStream;
036import javax.sound.sampled.AudioSystem;
037import javax.sound.sampled.DataLine;
038import javax.sound.sampled.LineUnavailableException;
039import javax.sound.sampled.TargetDataLine;
040import javax.sound.sampled.UnsupportedAudioFileException;
041
042///////////////////////////////////////////////////////////////////
043//// SoundCapture
044
045/**
046 A buffer supporting the capturing of audio samples from a file or
047 from the computer's audio input port.
048
049 <h2>Overview</h2>
050
051 <p>A buffer supporting the capturing of audio samples from a file or
052 from the computer's audio input port. This class supports the
053 real-time capture of audio from the audio input port (mic or line-in)
054 as well as the capture of audio from a sound file specified as a
055 URL. Single channel (mono) and multichannel audio (stereo) are
056 supported. This class, along with SoundPlayback, intends to provide
057 an easy to use interface to Java Sound, Java's audio API. Java Sound
058 supports the capture of audio data, but only at the byte level, which
059 is audio format specific. This class, however, provides higher level
060 support for the capture of double or integer valued samples from the
061 computer's audio input port or any supported sound file type. This
062 class is therefore useful when it one desires to capture audio
063 samples in an audio format independent way.</p>
064
065 <p>Depending on available audio system resources, it may be possible
066 to run an instance of this class and an instance of SoundPlayback
067 concurrently. This allows for the concurrent capture, signal
068 processing, and playback of audio data.</p>
069
070 <h2>Usage</h2>
071
072 <p>Two constructors are provided. One constructor creates a sound
073 capture object that captures from the line-in or microphone port.
074 The operating system must be used to select between the microphone
075 and line-in. This cannot be done using Java. If this constructor is
076 used, there will be a small delay between the time that the audio
077 enters the microphone or line-in and the time that the corresponding
078 audio samples are available via getSamples() or getSamplesInt().
079 This latency can be adjusted by setting the <i>bufferSize</i>
080 constructor parameter. Another constructor creates a sound capture
081 object that captures audio from a sound file specified as a URL.</p>
082
083 <p> After calling the appropriate constructor, startCapture() must be
084 called to initialize the audio system for capture.  The getSamples()
085 or getSamplesInt() method should then be repeatedly invoked to obtain
086 audio data in the form of a multidimensional array of audio sample
087 values. getSamples() will return audio sample values in the range
088 [-1, 1]. getSamplesInt() will return audio samples in the range
089 (-2^(bits_per_sample/2), 2^(bits_per_sample/2)), where
090 bits_per_sample is the number of bits per sample.  For the case where
091 audio is captured from the mic or line-in, it is important to invoke
092 getSamples() or getSamplesInt() often enough to prevent overflow of
093 the internal audio buffer. The size of the internal buffer is set in
094 the constructor. Note that it is possible (but probably not useful)
095 to interleave calls to getSamples() and getSamplesInt().  Finally,
096 after no more audio data is desired, stopCapture() should be called
097 to free up audio system resources.</p>
098
099 <h2>Security issues</h2>
100
101 <p> Applications have no restrictions on the
102 capturing or playback of audio. Applets, however, may only capture
103 audio from a file specified as a URL on the same machine as the
104 one the applet was loaded from. Applet code is not allowed to
105 read or write native files. The .java.policy file must be
106 modified to grant applets more privileges.</p>
107
108 @author Brian K. Vogel
109 @version $Id$
110 @since Ptolemy II 1.0
111 @Pt.ProposedRating Yellow (vogel)
112 @Pt.AcceptedRating Yellow (cxh)
113 @see ptolemy.media.javasound.SoundPlayback
114 */
115public class SoundCapture {
116    /** Construct a sound capture object that captures audio from a computer's
117     *  audio input port.  If this constructor is used, then it
118     *  is important that getSamples() be
119     *  invoked often enough to prevent overflow of the internal audio
120     *  input buffer. Note the startCapture() must be called before the
121     *  first invocation of getSamples(), otherwise getSamples() will
122     *  throw an exception.
123     *  @param sampleRate Sample rate in Hz. Must be in the range: 8000
124     *   to 48000.
125     *  @param sampleSizeInBits Number of bits per sample. Choices are
126     *   8 or 16.
127     *  @param channels Number of audio channels. 1 for mono, 2 for
128     *   stereo.
129     *  @param bufferSize Requested size of the internal audio input
130     *   buffer in samples. This controls the latency. A lower bound
131     *   on the latency is given by (<i>bufferSize</i> / <i>sampleRate</i>)
132     *   seconds. Ideally, the
133     *   smallest value that gives acceptable performance (no overflow)
134     *   should be used. Typical values are about 1/10 th the sample
135     *   rate. For example, at 44100 Hz sample rate, a typical buffer
136     *   size value might be 4410.
137     *  @param getSamplesSize Size of the array returned by
138     *   getSamples(). For performance reasons, the size should
139     *   be chosen smaller than <i>bufferSize</i>. Typical values
140     *   are 1/2 to 1/16th of <i>bufferSize</i>.
141     */
142    public SoundCapture(float sampleRate, int sampleSizeInBits, int channels,
143            int bufferSize, int getSamplesSize) {
144        _isAudioCaptureActive = false;
145
146        // Set mode to real-time.
147        this._isRealTime = true;
148        this._sampleSizeInBits = sampleSizeInBits;
149        this._sampleRate = sampleRate;
150        this._channels = channels;
151        this._bufferSize = bufferSize;
152        this._productionRate = getSamplesSize;
153    }
154
155    /** Construct a sound capture object that captures audio from a
156     *  sound file specified as a URL. Note that it is still possible
157     *  to capture audio from a file on the local file system. For
158     *  example, to capture from a sound file located at
159     *  "C:\someDir\someFile.wave", <i>pathName</i>
160     *  should be set to "file:///C:/someDir/someFile.wave".
161     *  <p>
162     *  Note the startCapture() must be called before the
163     *  first invocation of getSamples(), otherwise getSamples() will
164     *  throw an exception.
165     *
166     *  @param pathName The name of the file as a URL. Valid sound file
167     *   formats are WAVE (.wav), AIFF (.aif, .aiff), AU (.au). The file
168     *   format is automatically determined from the file extension.
169     *   If there is a problem reading the sound file, an IOException
170     *   will be thrown in startCapture().
171     *  @param getSamplesSize The number of samples per channel
172     *   returned by getSamples().
173     */
174    public SoundCapture(String pathName, int getSamplesSize) {
175        _isAudioCaptureActive = false;
176
177        // Set mode to "capture from file" (not real-time).
178        this._isRealTime = false;
179        this._pathName = pathName;
180        this._productionRate = getSamplesSize;
181    }
182
183    ///////////////////////////////////////////////////////////////////
184    ///  Public Methods                                         ///
185
186    /** Return the number of audio channels. This method will
187     *  return the number of audio channels, regardless of
188     *  which constructor was used. However, this method is
189     *  really only useful when the constructor that causes
190     *  audio to be captured from a file is used, since
191     *  the number of channels is unknown until the file
192     *  is opened.
193     *  <p>
194     *  This method should
195     *  be called while audio capture is active, i.e., after
196     *  startCapture() is called and before stopCapture()
197     *  is called.
198     *
199     *  @return The number of audio channels. Return null if
200     *   this method is called before startCapture().
201     *
202     *  @exception IllegalStateException If this method is called
203     *   before startCapture() is called or after stopCapture()
204     *   is called.
205     */
206    public int getChannels() throws IllegalStateException {
207        if (_isAudioCaptureActive == true) {
208            return _channels;
209        }
210        throw new IllegalStateException("SoundCapture: "
211                + "getChannels() was called while audio capture was"
212                + " inactive (startCapture() was never called).");
213    }
214
215    /** Return the sampling rate in Hz. This method will
216     *  return the sampling rate, regardless of
217     *  which constructor was used. However, this method is
218     *  really only useful when the constructor that causes
219     *  audio to be captured from a file is used, since
220     *  the sampling rate is unknown until the file
221     *  is opened.
222     *  <p>
223     *  This method should
224     *  be called while audio capture is active, i.e., after
225     *  startCapture() is called and before stopCapture()
226     *  is called.
227     *
228     *  @return The sample rate in Hz. Return null if
229     *   this method is called before startCapture().
230     *
231     *  @exception IllegalStateException If this method is called
232     *   before startCapture() is called or after stopCapture()
233     *   is called.
234     */
235    public float getSampleRate() throws IllegalStateException {
236        if (_isAudioCaptureActive == true) {
237            return _sampleRate;
238        }
239        throw new IllegalStateException("SoundCapture: "
240                + "getSampleRate() was called while audio capture was"
241                + " inactive (startCapture() was never called).");
242    }
243
244    /** Return an array of captured audio samples. This method
245     *  should be repeatedly called to obtain audio data.
246     *  The returned audio samples will have values in the range
247     *  [-1, 1], regardless of the audio bit resolution (bits per
248     *  sample). When
249     *  capturing from the computer's audio input port (mic or
250     *  line-in), this method should be called often enough to
251     *  prevent overflow of the internal audio buffer. If
252     *  overflow occurs, some audio data will be lost but no
253     *  exception or other error condition will occur. If
254     *  the audio data is not yet available, then this method
255     *  will block until the data is available. When capturing
256     *  from a sound file, it is not possible for overflow to
257     *  occur.
258     *  <p>
259     *  The array size
260     *  is set by the <i>getSamplesSize</i> parameter in the
261     *  constructor. For the case where audio is captured from
262     *  the computer's audio-in port (mic or line-in), this
263     *  method should be called often enough to prevent overflow
264     *  of the internal audio buffer, the size of which is set
265     *  in the constructor.
266     *  @return Two dimensional array of captured audio samples.
267     *   Return null
268     *  if end of audio file is reached. A null return value is
269     *  only possible when capturing from a sound file.
270     *  The first index
271     *  represents the channel number (0 for first channel, 1 for
272     *  second channel, etc.). The second index represents the
273     *  sample index within a channel. For example,
274     *  <i>returned array</i>[n][m] contains the (m+1)th sample
275     *  of the (n+1)th channel. For each channel, n, the length of
276     *  <i>returned array</i>[n] is equal to <i>getSamplesSize</i>.
277     *
278     *  @exception IOException If there is a problem capturing audio.
279     *  @exception IllegalStateException If audio capture is currently
280     *  inactive. That is, If startCapture() has not yet been called
281     *  or if stopCapture() has already been called.
282     */
283    public double[][] getSamples() throws IOException, IllegalStateException {
284        if (_isAudioCaptureActive == true) {
285            int numBytesRead;
286
287            if (_isRealTime == true) {
288                // Real-time capture.
289                numBytesRead = _targetLine.read(_data, 0,
290                        _productionRate * _frameSizeInBytes);
291            } else {
292                // Capture audio from file.
293                numBytesRead = _properFormatAudioInputStream.read(_data);
294            }
295
296            if (numBytesRead == _data.length) {
297                // Convert byte array to double array.
298                _audioInDoubleArray = _byteArrayToDoubleArray(_data,
299                        _bytesPerSample, _channels);
300                return _audioInDoubleArray;
301            } else if (numBytesRead != _data.length) {
302                // Read fewer samples than productionRate many samples.
303                // FIXME: There appears to be a java sound bug that
304                // causes AudioInputStream.read(array) to sometimes
305                // return fewer bytes than requested, even though
306                // the end of the file has not yet been reached.
307                _audioInDoubleArray = _byteArrayToDoubleArray(_data,
308                        _bytesPerSample, _channels);
309                return _audioInDoubleArray;
310            } else if (numBytesRead == -1) {
311                // Ran out of samples to play. This generally means
312                // that the end of the sound file has been reached.
313                return null;
314            }
315
316            return null;
317        }
318        throw new IllegalStateException("SoundCapture: "
319                + "getSamples() was called while audio capture was"
320                + " inactive (startCapture() was never called or "
321                + "stopCapture has already been called).");
322    }
323
324    /** Return an array of captured audio samples. This method
325     *  should be repeatedly called to obtain audio data. This
326     *  method requires less computation than getSamples(),
327     *  since no conversion to doubles is performed. Therefore,
328     *  the use of this method is recommended when integer
329     *  valued audio samples are sufficient. The
330     *  returned audio samples will have values in the range
331     *  (-2^(bits_per_sample/2), 2^(bits_per_sample/2)). The
332     *  range of sample values returned is therefore dependent
333     *  on the bit resolution of the audio data. If this is not
334     *  desired, then use getSamples() instead.
335     *  <p>
336     *  When capturing from the computer's audio input port (mic or
337     *  line-in), this method should be called often enough to
338     *  prevent overflow of the internal audio buffer. If
339     *  overflow occurs, some audio data will be lost but no
340     *  exception or other error condition will occur. If
341     *  the audio data is not yet available, then this method
342     *  will block until the data is available. When capturing
343     *  from a sound file, it is not possible for overflow to
344     *  occur.
345     *  <p> The  array size
346     *  is set by the <i>getSamplesSize</i> parameter in the
347     *  constructor. For the case where audio is captured from
348     *  the computer's audio-in port (mic or line-in), this
349     *  method should be called often enough to prevent overflow
350     *  of the internal audio buffer, the size of which is set
351     *  in the constructor.
352     *  @return Two dimensional array of captured audio samples.
353     *   Return null
354     *  if end of audio file is reached A null return value is
355     *  only possible when capturing from a sound file.
356     *  The first index
357     *  represents the channel number (0 for first channel, 1 for
358     *  second channel, etc.). The second index represents the
359     *  sample index within a channel. For example,
360     *  <i>returned array</i>[n][m] contains the (m+1)th sample
361     *  of the (n+1)th channel. For each channel, n, the length of
362     *  <i>returned array</i>[n] is equal to <i>getSamplesSize</i>.
363     *
364     *  @exception IOException If there is a problem capturing audio.
365     *  @exception IllegalStateException If audio capture is currently
366     *  inactive. That is, If startCapture() has not yet been called
367     *  or if stopCapture() has already been called.
368     */
369    public int[][] getSamplesInt() throws IOException, IllegalStateException {
370        if (_isAudioCaptureActive == true) {
371            int numBytesRead;
372
373            if (_isRealTime == true) {
374                // Real-time capture.
375                numBytesRead = _targetLine.read(_data, 0,
376                        _productionRate * _frameSizeInBytes);
377            } else {
378                // Capture audio from file.
379                numBytesRead = _properFormatAudioInputStream.read(_data);
380            }
381
382            if (numBytesRead == _data.length) {
383                // Convert byte array to double array.
384                _audioInIntArray = _byteArrayToIntArray(_data, _bytesPerSample,
385                        _channels);
386                return _audioInIntArray;
387            } else if (numBytesRead != _data.length) {
388                // Read fewer samples than productionRate many samples.
389                // FIXME: Output the samples that were read + zeros?
390                return null;
391            } else if (numBytesRead == -1) {
392                // Ran out of samples to play. This generally means
393                // that the end of the sound file has been reached.
394                return null;
395            }
396
397            return null;
398        }
399        throw new IllegalStateException("SoundCapture: "
400                + "getSamples() was called while audio capture was"
401                + " inactive (startCapture() was never called or "
402                + "stopCapture has already been called).");
403    }
404
405    /** Begin capturing audio. This method must be invoked prior
406     *  to the first invocation of getSamples(). If this is not
407     *  done, then getSamples() will throw an exception when
408     *  it is invoked. It is safe
409     *  to call getSamples() immediately after this method returns.
410     *  This method must not be called more than
411     *  once between invocations of stopCapture(). Calling
412     *  this method more than once between invocations of
413     *  stopCapture() will cause this method to throw an exception.
414     *
415     *  @exception IOException If there is a problem setting up
416     *  the system for audio capture. This will occur if the
417     *  a URL cannot be opened or if the audio in port cannot
418     *  be accessed.
419     *  @exception IllegalStateException If this method is called
420     *  more than once between invocations of stopCapture().
421     */
422    public void startCapture() throws IOException, IllegalStateException {
423        if (_isAudioCaptureActive == false) {
424            // FIXME: check and throw Exceptions
425            if (_isRealTime == true) {
426                _startCaptureRealTime();
427            } else {
428                _startCaptureFromFile();
429            }
430
431            _isAudioCaptureActive = true;
432        } else {
433            throw new IllegalStateException("SoundCapture: "
434                    + "startCapture() was called while audio capture was"
435                    + " already active (startCapture() was called "
436                    + "more than once between invocations of stopCapture()).");
437        }
438    }
439
440    /** Stop capturing audio. This method should be called when
441     *  no more calls to getSamples(). are required, so
442     *  that the system resources involved in the audio capture
443     *  may be freed.
444     *
445     *  @exception IOException If there is a problem closing the
446     *  audio resources.
447     */
448    public void stopCapture() throws IOException {
449        if (_isAudioCaptureActive == true) {
450            // Free up audio system resources.
451            // For capture from file:
452            if (_audioInputStream != null) {
453                _audioInputStream.close();
454
455                // FIXME : is this correct?
456                _audioInputStream = null;
457            }
458
459            if (_properFormatAudioInputStream != null) {
460                _properFormatAudioInputStream.close();
461
462                // FIXME : is this correct?
463                _properFormatAudioInputStream = null;
464            }
465
466            // For real-time capture:
467            if (_targetLine != null) {
468                if (_targetLine.isOpen() == true) {
469                    _targetLine.stop();
470                    _targetLine.close();
471                    _targetLine = null;
472                }
473            }
474        }
475
476        _isAudioCaptureActive = false;
477    }
478
479    /** Return the number of bits per audio sample. This method will
480     *  return the number of bits per audio sample, regardless of
481     *  which constructor was used. However, this method is
482     *  really only useful when the constructor that causes
483     *  audio to be captured from a file is used, since
484     *  the number of bits per audio sample is unknown until the file
485     *  is opened.
486     *  <p>
487     *  This method must
488     *  be called while audio capture is active, i.e., after
489     *  startCapture() is called and before stopCapture()
490     *  is called, or else an exception will be thrown.
491     *
492     * @return The sample size in bits. Return null if
493     *  this method is called before startCapture().
494     *
495     * @exception IllegalStateException If this method is called
496     *  before startCapture() is called or after stopCapture()
497     *  is called.
498     */
499    public int getSampleSizeInBits() throws IllegalStateException {
500        if (_isAudioCaptureActive == true) {
501            return _sampleSizeInBits;
502        }
503        throw new IllegalStateException("SoundCapture: "
504                + "getSampleSizeInBits() was called while audio capture was"
505                + " inactive (startCapture() was never called).");
506    }
507
508    ///////////////////////////////////////////////////////////////////
509    ////                         private methods                   ////
510    private void _startCaptureRealTime() throws IOException {
511        boolean signed = true;
512        boolean bigEndian = true;
513
514        AudioFormat format = new AudioFormat(_sampleRate, _sampleSizeInBits,
515                _channels, signed, bigEndian);
516
517        _frameSizeInBytes = format.getFrameSize();
518
519        DataLine.Info targetInfo = new DataLine.Info(TargetDataLine.class,
520                format, AudioSystem.NOT_SPECIFIED);
521
522        // The following works under Windows Java 1.3.0 RC2 but
523        // not under Tritonus under Linux, so comment out.
524        //if (!AudioSystem.isLineSupported(targetInfo)) {
525        //    // FIXME: throw exception here.
526        //    System.out.println("Line matching " + targetInfo +
527        //            " not supported.");
528        //    return;
529        //}
530        try {
531            _targetLine = (TargetDataLine) AudioSystem.getLine(targetInfo);
532
533            // Note: 2nd parameter is the buffer size (in bytes).
534            // Larger values increase latency but may be required if
535            // garbage collection, etc. is an issue.
536            _targetLine.open(format, _bufferSize * _frameSizeInBytes);
537        } catch (LineUnavailableException ex) {
538            throw new IOException("Unable to open the line for "
539                    + "real-time audio capture: " + ex);
540        }
541
542        // The following works under Windows Java 1.3.0 RC2 but
543        // not under Tritonus under Linux, so comment out.
544        //if (!AudioSystem.isLineSupported(sourceInfo)) {
545        //    //FIXME: handle this correctly.
546        //    System.err.println("Line matching " + sourceInfo +
547        //            " not supported.");
548        //    return;
549        //}
550        // Array of audio samples in byte format.
551        _data = new byte[_productionRate * _frameSizeInBytes];
552
553        _bytesPerSample = _sampleSizeInBits / 8;
554
555        // Start the target data line
556        _targetLine.start();
557    }
558
559    /* Perform necessary initialization to capture from a sound
560     * file. The sound file is specified as a URL.
561     */
562    private void _startCaptureFromFile() throws IOException {
563        // Load audio from a URL.
564        // Create a URL corresponding to the sound file location.
565        URL soundURL = new URL(_pathName);
566
567        if (soundURL != null) {
568            try {
569                _audioInputStream = AudioSystem.getAudioInputStream(soundURL);
570            } catch (UnsupportedAudioFileException e) {
571                throw new IOException("Unsupported AudioFile :" + e);
572            }
573        }
574
575        // make sure we have something to play
576        if (_audioInputStream == null) {
577            throw new IOException("No loaded audio to play back");
578        }
579
580        // FIXME: is this correct?
581        //_audioInputStream.reset();
582        AudioFormat origFormat = _audioInputStream.getFormat();
583
584        // Now convert to PCM_SIGNED_BIG_ENDIAN so that can get double
585        // representation of samples.
586        float sampleRate = origFormat.getSampleRate();
587
588        _sampleSizeInBits = origFormat.getSampleSizeInBits();
589        _bytesPerSample = _sampleSizeInBits / 8;
590
591        _channels = origFormat.getChannels();
592
593        boolean signed = true;
594        boolean bigEndian = true;
595        AudioFormat format = new AudioFormat(sampleRate, _sampleSizeInBits,
596                _channels, signed, bigEndian);
597        _properFormatAudioInputStream = AudioSystem.getAudioInputStream(format,
598                _audioInputStream);
599
600        _frameSizeInBytes = format.getFrameSize();
601
602        // FIXME: is this correct?
603        //_properFormatAudioInputStream.reset();
604        // Array of audio samples in byte format.
605        _data = new byte[_productionRate * _frameSizeInBytes];
606    }
607
608    /* Convert a byte array of audio samples in linear signed pcm big endian
609     * format into a double array of audio samples (-1, 1) range.
610     * @param byteArray  The linear signed pcm big endian byte array
611     * formatted array representation of audio data.
612     * @param bytesPerSample Number of bytes per sample. Supported
613     * bytes per sample by this method are 8, 16, 24, 32.
614     * @param channels Number of audio channels. 1 for mono, 2 for
615     * stereo.
616     * @return Two dimensional array holding audio samples.
617     * For each channel, m, doubleArray[m] is a single dimensional
618     * array containing samples for channel m.
619     */
620    private double[][] _byteArrayToDoubleArray(byte[] byteArray,
621            int bytesPerSample, int channels) {
622        int lengthInSamples = byteArray.length / (bytesPerSample * channels);
623
624        // Check if we need to reallocate.
625        if (channels != _doubleArray.length
626                || lengthInSamples != _doubleArray[0].length) {
627            // Reallocate
628            _doubleArray = new double[channels][lengthInSamples];
629        }
630
631        //double maxSampleReciprocal = 1/(Math.pow(2, 8 * bytesPerSample - 1));
632        // Could use above line, but hopefully, code below will
633        // be faster.
634        double maxSampleReciprocal;
635
636        if (bytesPerSample == 2) {
637            // 1 / 32768
638            maxSampleReciprocal = 3.0517578125e-5;
639        } else if (bytesPerSample == 1) { // 1 / 128
640            maxSampleReciprocal = 7.8125e-3;
641        } else if (bytesPerSample == 3) {
642            // 1 / 8388608
643            maxSampleReciprocal = 1.1920928955e07;
644        } else if (bytesPerSample == 4) {
645            // 1 / 147483648e9
646            maxSampleReciprocal = 4.655661287308e-10;
647        } else {
648            // Should not happen.
649            maxSampleReciprocal = 0;
650        }
651
652        // Check if we need to reallocate.
653        // FIXME: This test is really not needed since bytesPerSample
654        // is set in the constructor. It should never change.
655        if (bytesPerSample != _b.length) {
656            _b = new byte[bytesPerSample];
657        }
658
659        for (int currSamp = 0; currSamp < lengthInSamples; currSamp++) {
660            // For each channel,
661            for (int currChannel = 0; currChannel < channels; currChannel++) {
662                for (int i = 0; i < bytesPerSample; i += 1) {
663                    // Assume we are dealing with big endian.
664                    _b[i] = byteArray[currSamp * bytesPerSample * channels
665                            + bytesPerSample * currChannel + i];
666                }
667
668                int result = _b[0] >> 7;
669
670                for (int i = 0; i < bytesPerSample; i += 1) {
671                    result = (result << 8) + (_b[i] & 0xff);
672                }
673
674                _doubleArray[currChannel][currSamp] = result
675                        * maxSampleReciprocal;
676            }
677        }
678
679        return _doubleArray;
680    }
681
682    /* Convert a byte array of audio samples in linear signed pcm big endian
683     * format into a (signed) int array of audio samples. The range
684     * of the returned samples is approximately
685     * (-2^(bits_per_sample/2), 2^(bits_per_sample/2)).
686     * @param byteArray  The linear signed pcm big endian byte array
687     * formatted array representation of audio data.
688     * @param bytesPerSample Number of bytes per sample. Supported
689     * bytes per sample by this method are 8, 16, 24, 32.
690     * @param channels Number of audio channels. 1 for mono, 2 for
691     * stereo.
692     * @return Two dimensional array holding audio samples.
693     * For each channel, m, intArray[m] is a single dimensional
694     * array containing samples for channel m.
695     */
696    private int[][] _byteArrayToIntArray(byte[] byteArray, int bytesPerSample,
697            int channels) {
698        int lengthInSamples = byteArray.length / (bytesPerSample * channels);
699
700        // Check if we need to reallocate.
701        if (channels != _doubleArray.length
702                || lengthInSamples != _doubleArray[0].length) {
703            // Reallocate
704            _intArray = new int[channels][lengthInSamples];
705        }
706
707        // Check if we need to reallocate.
708        // FIXME: This test is really not needed since bytesPerSample
709        // is set in the constructor. It should never change.
710        if (bytesPerSample != _b.length) {
711            _b = new byte[bytesPerSample];
712        }
713
714        for (int currSamp = 0; currSamp < lengthInSamples; currSamp++) {
715            // For each channel,
716            for (int currChannel = 0; currChannel < channels; currChannel++) {
717                for (int i = 0; i < bytesPerSample; i += 1) {
718                    // Assume we are dealing with big endian.
719                    _b[i] = byteArray[currSamp * bytesPerSample * channels
720                            + bytesPerSample * currChannel + i];
721                }
722
723                int result = _b[0] >> 7;
724
725                for (int i = 0; i < bytesPerSample; i += 1) {
726                    result = (result << 8) + (_b[i] & 0xff);
727                }
728
729                _intArray[currChannel][currSamp] = result;
730            }
731        }
732
733        return _intArray;
734    }
735
736    ///////////////////////////////////////////////////////////////////
737    ////                         private variables                 ////
738    private AudioInputStream _properFormatAudioInputStream;
739
740    private AudioInputStream _audioInputStream;
741
742    private int _productionRate;
743
744    // Array of audio samples in double format.
745    private double[][] _audioInDoubleArray;
746
747    // Array of audio samples in int format.
748    private int[][] _audioInIntArray;
749
750    // Array of audio samples in byte format.
751    private byte[] _data;
752
753    private int _frameSizeInBytes;
754
755    private boolean _isRealTime;
756
757    private String _pathName;
758
759    private int _sampleSizeInBits;
760
761    private float _sampleRate;
762
763    private int _channels;
764
765    private int _bufferSize;
766
767    private TargetDataLine _targetLine;
768
769    private int _bytesPerSample;
770
771    private boolean _isAudioCaptureActive;
772
773    private byte[] _b = new byte[1];
774
775    private double[][] _doubleArray = new double[1][1];
776
777    private int[][] _intArray = new int[1][1];
778}