001/*
002 Class containing the platform independent code of LiveSound.
003
004 Copyright (c) 2011-2014 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.util.Iterator;
032import java.util.LinkedList;
033import java.util.List;
034
035///////////////////////////////////////////////////////////////////
036//// LiveSoundCommon
037
038/**
039Class containing the platform independent code of LiveSound actor.
040
041@author Brian K. Vogel and Neil E. Turner and Steve Neuendorffer, Edward A. Lee, Contributor: Dennis Geurts, Ishwinder Singh
042@version $Id$
043@since Ptolemy II 10.0
044@Pt.ProposedRating Red (ishwinde)
045@Pt.AcceptedRating Red (ishwinde)
046 */
047public class LiveSoundCommon {
048
049    /** Add a live sound listener. The listener will be notified
050     *  of all changes in live audio parameters. If the listener
051     *  is already listening, then do nothing.
052     *
053     *  @param listener The LiveSoundListener to add.
054     *  @see #removeLiveSoundListener(LiveSoundListener)
055     */
056    public void addLiveSoundListener(LiveSoundListener listener) {
057        if (!_liveSoundListeners.contains(listener)) {
058            _liveSoundListeners.add(listener);
059        }
060    }
061
062    /** Return the number of bits per sample.
063     *  @return The number of bits per sample, which in this base
064     *  class defaults to 16.
065     */
066    public int getBitsPerSample() {
067        return _bitsPerSample;
068    }
069
070    /** Return the suggested size of the internal capture and playback audio
071     *  buffers, in samples per channel. This parameter is set by the
072     *  setBufferSize() method.  There is no guarantee that the value returned
073     *  is the actual buffer size used for capture and playback.
074     *  Furthermore, the buffers used for capture and playback may have
075     *  different sizes.  The default value of this parameter is 4096.
076     *
077     *  @return The suggested internal buffer size in samples per
078     *   channel.
079     */
080    public int getBufferSize() {
081        return _bufferSize;
082    }
083
084    /** Return the number of audio channels, which is set by
085     *  the setChannels() method. The default value of this
086     *  parameter is 1 (for mono audio).
087     *
088     *  @return The number of audio channels.
089     */
090    public int getChannels() {
091        return _channels;
092    }
093
094    /** Return the current sampling rate in Hz, which is set
095     *  by the setSampleRate() method. The default value of
096     *  this parameter is 8000 Hz.
097     *
098     *  @return The sample rate in Hz.
099     */
100    public int getSampleRate() {
101        return (int) _sampleRate;
102    }
103
104    /** Get the array length (in samples per channel) to use
105     *  for capturing and playing samples via the putSamples()
106     *  and getSamples() methods. This method gets the size
107     *  of the 2nd dimension of the 2-dimensional array
108     *  used by the putSamples() and getSamples() methods. This
109     *  method returns the value that was set by the
110     *  setTransferSize(). If setTransferSize() was not invoked,
111     *  the default value of 128 is returned.
112     *
113     *  @return The size of the 2nd dimension of the 2-dimensional
114     *   array used by the putSamples() and getSamples() methods.
115     *  @see #setTransferSize(int)
116     */
117    public int getTransferSize() {
118        return _transferSize;
119    }
120
121    /** Return true if audio capture is currently active.
122     *  Otherwise return false.
123     *
124     *  @return True If audio capture is currently active.
125     *  Otherwise return false.
126     */
127    public boolean isCaptureActive() {
128        return _captureIsActive;
129    }
130
131    /** Return true if audio playback is currently active.
132     *  Otherwise return false.
133     *
134     *  @return True If audio playback is currently active.
135     *  Otherwise return false.
136     */
137    public boolean isPlaybackActive() {
138        return _playbackIsActive;
139    }
140
141    /** Remove a live sound listener. If the listener is
142     *  is not listening, then do nothing.
143     *
144     *  @param listener The LiveSoundListener to remove.
145     *  @see #addLiveSoundListener(LiveSoundListener)
146     */
147    public void removeLiveSoundListener(LiveSoundListener listener) {
148        if (_liveSoundListeners.contains(listener)) {
149            _liveSoundListeners.remove(listener);
150        }
151    }
152
153    /** Set the array length (in samples per channel) to use
154     *  for capturing and playing samples via the putSamples()
155     *  and getSamples() methods. This method sets the size
156     *  of the 2nd dimension of the 2-dimensional array
157     *  used by the putSamples() and getSamples() methods. If
158     *  this method is not invoked, the default value of 128 is
159     *  used.
160     *  <p>
161     *  This method should only be called while audio capture and
162     *  playback are inactive. Otherwise an exception will occur.
163     *
164     *  @param transferSize The  size of the 2nd dimension of
165     *   the 2-dimensional array used by the putSamples() and
166     *   getSamples() methods
167     *
168     *  @exception IllegalStateException If this method is called
169     *   while audio capture or playback are active.
170     *  @see #getTransferSize()
171     */
172    public void setTransferSize(int transferSize) throws IllegalStateException {
173        // This change only affects capture, so it's OK for it to occur
174        // while there is playback.
175        if (_captureIsActive) {
176            throw new IllegalStateException("LiveSound: "
177                    + "setTransferSize() was called while audio capture "
178                    + "or playback was active.");
179        } else {
180            _transferSize = transferSize;
181        }
182    }
183
184    /** Convert a byte array of audio samples in linear signed PCM big endian
185     * format into a double array of audio samples (-1, 1) range.
186     * @param doubleArray The resulting array of doubles.
187     * @param byteArray  The linear signed pcm big endian byte array
188     * formatted array representation of audio data.
189     */
190    protected void _byteArrayToDoubleArray(double[][] doubleArray,
191            byte[] byteArray) {
192        int lengthInSamples = byteArray.length / (_bytesPerSample * _channels);
193
194        for (int currSamp = 0; currSamp < lengthInSamples; currSamp++) {
195            // For each channel,
196            for (int currChannel = 0; currChannel < _channels; currChannel++) {
197                // Starting index of relevant bytes.
198                int j = currSamp * _bytesPerSample * _channels
199                        + _bytesPerSample * currChannel;
200                // Note: preserve sign of high order bits.
201                int result = byteArray[j++];
202
203                // Shift and add in low order bits.
204                // Note that it is ok to fall through the cases here (I think).
205                switch (_bytesPerSample) {
206                case 4:
207                    result <<= 8;
208                    // Dennis Geurts:
209                    // Use & instead of | here.
210                    // Running ptolemy/actor/lib/javasound/test/auto/testAudioCapture_AudioPlayer.xml
211                    // results in a much better sound.
212                    // See https://chess.eecs.berkeley.edu/bugzilla/show_bug.cgi?id=356
213                    result += byteArray[j++] & 0xff;
214
215                case 3:
216                    result <<= 8;
217                    result += byteArray[j++] & 0xff;
218
219                case 2:
220                    result <<= 8;
221                    result += byteArray[j++] & 0xff;
222                }
223
224                doubleArray[currChannel][currSamp] = result
225                        * _maxSampleReciprocal;
226            }
227        }
228    }
229
230    /** Convert a double array of audio samples into a byte array of
231     * audio samples in linear signed PCM big endian format. The
232     * samples contained in <i>doubleArray</i> should be in the
233     * range (-1, 1). Samples outside this range will be hard clipped
234     * to the range (-1, 1).
235     * @param doubleArray Two dimensional array holding audio samples.
236     *  For each channel, m, doubleArray[m] is a single dimensional
237     *  array containing samples for channel m. All channels are
238     *  required to have the same number of samples, but this is
239     *  not checked.
240     * @return The linear signed PCM big endian byte array formatted
241     *  array representation of <i>doubleArray</i>. The length of
242     *  the returned array is (doubleArray[i].length*bytesPerSample*channels).
243     */
244    protected byte[] _doubleArrayToByteArray(double[][] doubleArray) {
245        // This method is most efficient if repeated calls pass the same size
246        // array. In this case, it does not re-allocate the byte array that
247        // it returns, but rather reuses the same array on the heap.
248        int numberOfSamples = doubleArray[0].length;
249        int bufferSize = numberOfSamples * _bytesPerSample * _channels;
250        if (_playbackData == null || _playbackData.length != bufferSize) {
251            // Hopefully, the allocation is done only once.
252            _playbackData = new byte[bufferSize];
253        }
254        // Iterate over the samples.
255        for (int currSamp = 0; currSamp < doubleArray[0].length; currSamp++) {
256            // For each channel,
257            for (int currChannel = 0; currChannel < _channels; currChannel++) {
258                double sample = doubleArray[currChannel][currSamp];
259
260                // Perform clipping, if necessary.
261                if (sample > 1.0) {
262                    sample = 1.0;
263                } else if (sample < -1.0) {
264                    sample = -1.0;
265                }
266
267                // signed integer representation of current sample of the
268                // current channel.
269                // Note: Floor instead of cast to remove deadrange at zero.
270                int intValue = (int) Math.floor(sample * _maxSample);
271
272                int base = currSamp * _bytesPerSample * _channels
273                        + _bytesPerSample * currChannel;
274                // Create byte representation of current sample.
275                // Note: unsigned Shift right.
276                // Note: fall through from higher number cases.
277                switch (_bytesPerSample) {
278                case 4:
279                    _playbackData[base + 3] = (byte) intValue;
280                    intValue >>>= 8;
281                case 3:
282                    _playbackData[base + 2] = (byte) intValue;
283                    intValue >>>= 8;
284                case 2:
285                    _playbackData[base + 1] = (byte) intValue;
286                    intValue >>>= 8;
287                case 1:
288                    _playbackData[base] = (byte) intValue;
289                }
290            }
291        }
292        return _playbackData;
293    }
294
295    /** Notify the live sound listeners about a change in an audio
296     *  parameter.
297     *
298     *  @param parameter The audio parameter of LiveSound that
299     *   has changed. The value of parameter should be one of
300     *   LiveSoundEvent.SAMPLE_RATE, LiveSoundEvent.CHANNELS,
301     *   LiveSoundEvent.BUFFER_SIZE, or
302     *   LiveSoundEvent.BITS_PER_SAMPLE.
303     */
304    protected void _notifyLiveSoundListeners(int parameter) {
305        if (_liveSoundListeners.size() > 0) {
306            LiveSoundEvent event = new LiveSoundEvent(parameter);
307            Iterator listeners = _liveSoundListeners.iterator();
308
309            while (listeners.hasNext()) {
310                ((LiveSoundListener) listeners.next()).liveSoundChanged(event);
311            }
312        }
313    }
314
315    ///////////////////////////////////////////////////////////////////
316    ////                         private variables                 ////
317
318    /** Array of audio samples in double format. */
319    protected double[][] _audioInDoubleArray;
320
321    /** The number of bits per sample. Default is 16. */
322    protected int _bitsPerSample = 16;
323
324    /** The requested buffer size in samples per channel. */
325    protected int _bufferSize = 1024;
326
327    /** The number of bytes per sample, default 2. */
328    protected int _bytesPerSample = 2;
329
330    /** true is audio capture is currently active. */
331    protected boolean _captureIsActive = false;
332
333    /** The number of channels. Deafult is 1. */
334    protected int _channels = 1;
335
336    /** Array of audio samples in byte format. */
337    protected byte[] _captureData;
338
339    /** Byte buffer used for playback data. */
340    protected byte[] _playbackData;
341
342    /** The list of listeners. */
343    protected List _liveSoundListeners = new LinkedList();
344
345    /** Cached value of the maximum value scaling factor, default for
346     * 16 bits.
347     */
348    protected double _maxSampleReciprocal = 1.0 / 32768;
349
350    /** Cached value of the maximum integer value, default for 16
351     *  bits.
352     */
353    protected double _maxSample = 32767;
354
355    /** true is audio playback is currently active. */
356    protected boolean _playbackIsActive = false;
357
358    /** The sample rate. */
359    protected float _sampleRate;
360
361    /** The list of sound consumers. */
362    protected List _soundConsumers = new LinkedList();
363
364    /** The number of audio samples to transfer per channel when
365     * getSamples() is invoked. */
366    protected int _transferSize = 128;
367
368}