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}