jdk/src/share/classes/com/sun/media/sound/UlawCodec.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1999-2007 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package com.sun.media.sound;
       
    27 
       
    28 import java.io.InputStream;
       
    29 import java.io.IOException;
       
    30 
       
    31 import java.util.Vector;
       
    32 
       
    33 import javax.sound.sampled.AudioFormat;
       
    34 import javax.sound.sampled.AudioSystem;
       
    35 import javax.sound.sampled.AudioInputStream;
       
    36 
       
    37 
       
    38 /**
       
    39  * U-law encodes linear data, and decodes u-law data to linear data.
       
    40  *
       
    41  * @author Kara Kytle
       
    42  */
       
    43 public class UlawCodec extends SunCodec {
       
    44 
       
    45     /* Tables used for U-law decoding */
       
    46 
       
    47     final static byte ULAW_TABH[] = new byte[256];
       
    48     final static byte ULAW_TABL[] = new byte[256];
       
    49 
       
    50     private static final AudioFormat.Encoding[] ulawEncodings = {AudioFormat.Encoding.ULAW,
       
    51                                                                  AudioFormat.Encoding.PCM_SIGNED};
       
    52 
       
    53     private static final short seg_end [] = {0xFF, 0x1FF, 0x3FF,
       
    54                                              0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
       
    55 
       
    56     /**
       
    57      * Initializes the decode tables
       
    58      */
       
    59     static {
       
    60         for (int i=0;i<256;i++) {
       
    61             int ulaw = ~i;
       
    62             int t;
       
    63 
       
    64             ulaw &= 0xFF;
       
    65             t = ((ulaw & 0xf)<<3) + 132;
       
    66             t <<= ((ulaw & 0x70) >> 4);
       
    67             t = ( (ulaw&0x80) != 0 ) ? (132-t) : (t-132);
       
    68 
       
    69             ULAW_TABL[i] = (byte) (t&0xff);
       
    70             ULAW_TABH[i] = (byte) ((t>>8) & 0xff);
       
    71         }
       
    72     }
       
    73 
       
    74 
       
    75     /**
       
    76      * Constructs a new ULAW codec object.
       
    77      */
       
    78     public UlawCodec() {
       
    79         super(ulawEncodings, ulawEncodings);
       
    80     }
       
    81 
       
    82     /**
       
    83      */
       
    84     public AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat){
       
    85         if( AudioFormat.Encoding.PCM_SIGNED.equals(sourceFormat.getEncoding()) ) {
       
    86             if( sourceFormat.getSampleSizeInBits() == 16 ) {
       
    87                 AudioFormat.Encoding enc[] = new AudioFormat.Encoding[1];
       
    88                 enc[0] = AudioFormat.Encoding.ULAW;
       
    89                 return enc;
       
    90             } else {
       
    91                 return new AudioFormat.Encoding[0];
       
    92             }
       
    93         } else if (AudioFormat.Encoding.ULAW.equals(sourceFormat.getEncoding())) {
       
    94             if (sourceFormat.getSampleSizeInBits() == 8) {
       
    95                 AudioFormat.Encoding enc[] = new AudioFormat.Encoding[1];
       
    96                 enc[0] = AudioFormat.Encoding.PCM_SIGNED;
       
    97                 return enc;
       
    98             } else {
       
    99                 return new AudioFormat.Encoding[0];
       
   100             }
       
   101         } else {
       
   102             return new AudioFormat.Encoding[0];
       
   103         }
       
   104     }
       
   105 
       
   106 
       
   107     /**
       
   108      */
       
   109     public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat){
       
   110         if( (AudioFormat.Encoding.PCM_SIGNED.equals(targetEncoding)
       
   111              && AudioFormat.Encoding.ULAW.equals(sourceFormat.getEncoding()))
       
   112             ||
       
   113             (AudioFormat.Encoding.ULAW.equals(targetEncoding)
       
   114              && AudioFormat.Encoding.PCM_SIGNED.equals(sourceFormat.getEncoding()))) {
       
   115                 return getOutputFormats(sourceFormat);
       
   116             } else {
       
   117                 return new AudioFormat[0];
       
   118             }
       
   119     }
       
   120 
       
   121     /**
       
   122      */
       
   123     public AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding, AudioInputStream sourceStream){
       
   124         AudioFormat sourceFormat = sourceStream.getFormat();
       
   125         AudioFormat.Encoding sourceEncoding = sourceFormat.getEncoding();
       
   126 
       
   127         if (sourceEncoding.equals(targetEncoding)) {
       
   128             return sourceStream;
       
   129         } else {
       
   130             AudioFormat targetFormat = null;
       
   131             if (!isConversionSupported(targetEncoding,sourceStream.getFormat())) {
       
   132                 throw new IllegalArgumentException("Unsupported conversion: " + sourceStream.getFormat().toString() + " to " + targetEncoding.toString());
       
   133             }
       
   134             if (AudioFormat.Encoding.ULAW.equals(sourceEncoding) &&
       
   135                 AudioFormat.Encoding.PCM_SIGNED.equals(targetEncoding) ) {
       
   136                 targetFormat = new AudioFormat( targetEncoding,
       
   137                                                 sourceFormat.getSampleRate(),
       
   138                                                 16,
       
   139                                                 sourceFormat.getChannels(),
       
   140                                                 2*sourceFormat.getChannels(),
       
   141                                                 sourceFormat.getSampleRate(),
       
   142                                                 sourceFormat.isBigEndian());
       
   143             } else if (AudioFormat.Encoding.PCM_SIGNED.equals(sourceEncoding) &&
       
   144                        AudioFormat.Encoding.ULAW.equals(targetEncoding)) {
       
   145                 targetFormat = new AudioFormat( targetEncoding,
       
   146                                                 sourceFormat.getSampleRate(),
       
   147                                                 8,
       
   148                                                 sourceFormat.getChannels(),
       
   149                                                 sourceFormat.getChannels(),
       
   150                                                 sourceFormat.getSampleRate(),
       
   151                                                 false);
       
   152             } else {
       
   153                 throw new IllegalArgumentException("Unsupported conversion: " + sourceStream.getFormat().toString() + " to " + targetEncoding.toString());
       
   154             }
       
   155 
       
   156             return getAudioInputStream( targetFormat, sourceStream );
       
   157         }
       
   158     }
       
   159 
       
   160     /**
       
   161      * use old code...
       
   162      */
       
   163     public AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream sourceStream){
       
   164         return getConvertedStream(targetFormat, sourceStream);
       
   165     }
       
   166 
       
   167 
       
   168     // OLD CODE
       
   169 
       
   170     /**
       
   171      * Opens the codec with the specified parameters.
       
   172      * @param stream stream from which data to be processed should be read
       
   173      * @param outputFormat desired data format of the stream after processing
       
   174      * @return stream from which processed data may be read
       
   175      * @throws IllegalArgumentException if the format combination supplied is
       
   176      * not supported.
       
   177      */
       
   178     /*  public AudioInputStream getConvertedStream(AudioFormat outputFormat, AudioInputStream stream) { */
       
   179     private AudioInputStream getConvertedStream(AudioFormat outputFormat, AudioInputStream stream) {
       
   180         AudioInputStream cs = null;
       
   181 
       
   182         AudioFormat inputFormat = stream.getFormat();
       
   183 
       
   184         if( inputFormat.matches(outputFormat) ) {
       
   185             cs = stream;
       
   186         } else {
       
   187             cs = (AudioInputStream) (new UlawCodecStream(stream, outputFormat));
       
   188         }
       
   189         return cs;
       
   190     }
       
   191 
       
   192     /**
       
   193      * Obtains the set of output formats supported by the codec
       
   194      * given a particular input format.
       
   195      * If no output formats are supported for this input format,
       
   196      * returns an array of length 0.
       
   197      * @return array of supported output formats.
       
   198      */
       
   199     /*  public AudioFormat[] getOutputFormats(AudioFormat inputFormat) { */
       
   200     private AudioFormat[] getOutputFormats(AudioFormat inputFormat) {
       
   201 
       
   202         Vector formats = new Vector();
       
   203         AudioFormat format;
       
   204 
       
   205         if ((inputFormat.getSampleSizeInBits() == 16)
       
   206             && AudioFormat.Encoding.PCM_SIGNED.equals(inputFormat.getEncoding())) {
       
   207             format = new AudioFormat(AudioFormat.Encoding.ULAW,
       
   208                                      inputFormat.getSampleRate(),
       
   209                                      8,
       
   210                                      inputFormat.getChannels(),
       
   211                                      inputFormat.getChannels(),
       
   212                                      inputFormat.getSampleRate(),
       
   213                                      false );
       
   214             formats.addElement(format);
       
   215         }
       
   216 
       
   217         if (AudioFormat.Encoding.ULAW.equals(inputFormat.getEncoding())) {
       
   218             format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
       
   219                                      inputFormat.getSampleRate(),
       
   220                                      16,
       
   221                                      inputFormat.getChannels(),
       
   222                                      inputFormat.getChannels()*2,
       
   223                                      inputFormat.getSampleRate(),
       
   224                                      false );
       
   225             formats.addElement(format);
       
   226 
       
   227             format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
       
   228                                      inputFormat.getSampleRate(),
       
   229                                      16,
       
   230                                      inputFormat.getChannels(),
       
   231                                      inputFormat.getChannels()*2,
       
   232                                      inputFormat.getSampleRate(),
       
   233                                      true );
       
   234             formats.addElement(format);
       
   235         }
       
   236 
       
   237         AudioFormat[] formatArray = new AudioFormat[formats.size()];
       
   238         for (int i = 0; i < formatArray.length; i++) {
       
   239             formatArray[i] = (AudioFormat)(formats.elementAt(i));
       
   240         }
       
   241         return formatArray;
       
   242     }
       
   243 
       
   244 
       
   245     class UlawCodecStream extends AudioInputStream {
       
   246 
       
   247         private static final int tempBufferSize = 64;
       
   248         private byte tempBuffer [] = null;
       
   249 
       
   250         /**
       
   251          * True to encode to u-law, false to decode to linear
       
   252          */
       
   253         boolean encode = false;
       
   254 
       
   255         AudioFormat encodeFormat;
       
   256         AudioFormat decodeFormat;
       
   257 
       
   258         byte tabByte1[] = null;
       
   259         byte tabByte2[] = null;
       
   260         int highByte = 0;
       
   261         int lowByte  = 1;
       
   262 
       
   263         UlawCodecStream(AudioInputStream stream, AudioFormat outputFormat) {
       
   264             super(stream, outputFormat, AudioSystem.NOT_SPECIFIED);
       
   265 
       
   266             AudioFormat inputFormat = stream.getFormat();
       
   267 
       
   268             // throw an IllegalArgumentException if not ok
       
   269             if (!(isConversionSupported(outputFormat, inputFormat))) {
       
   270                 throw new IllegalArgumentException("Unsupported conversion: " + inputFormat.toString() + " to " + outputFormat.toString());
       
   271             }
       
   272 
       
   273             //$$fb 2002-07-18: fix for 4714846: JavaSound ULAW (8-bit) encoder erroneously depends on endian-ness
       
   274             boolean PCMIsBigEndian;
       
   275 
       
   276             // determine whether we are encoding or decoding
       
   277             if (AudioFormat.Encoding.ULAW.equals(inputFormat.getEncoding())) {
       
   278                 encode = false;
       
   279                 encodeFormat = inputFormat;
       
   280                 decodeFormat = outputFormat;
       
   281                 PCMIsBigEndian = outputFormat.isBigEndian();
       
   282             } else {
       
   283                 encode = true;
       
   284                 encodeFormat = outputFormat;
       
   285                 decodeFormat = inputFormat;
       
   286                 PCMIsBigEndian = inputFormat.isBigEndian();
       
   287                 tempBuffer = new byte[tempBufferSize];
       
   288             }
       
   289 
       
   290             // setup tables according to byte order
       
   291             if (PCMIsBigEndian) {
       
   292                 tabByte1 = ULAW_TABH;
       
   293                 tabByte2 = ULAW_TABL;
       
   294                 highByte = 0;
       
   295                 lowByte  = 1;
       
   296             } else {
       
   297                 tabByte1 = ULAW_TABL;
       
   298                 tabByte2 = ULAW_TABH;
       
   299                 highByte = 1;
       
   300                 lowByte  = 0;
       
   301             }
       
   302 
       
   303             // set the AudioInputStream length in frames if we know it
       
   304             if (stream instanceof AudioInputStream) {
       
   305                 frameLength = ((AudioInputStream)stream).getFrameLength();
       
   306             }
       
   307             // set framePos to zero
       
   308             framePos = 0;
       
   309             frameSize = inputFormat.getFrameSize();
       
   310             if (frameSize == AudioSystem.NOT_SPECIFIED) {
       
   311                 frameSize = 1;
       
   312             }
       
   313         }
       
   314 
       
   315 
       
   316         /*
       
   317          * $$jb 2/23/99
       
   318          * Used to determine segment number in uLaw encoding
       
   319          */
       
   320         private short search(short val, short table[], short size) {
       
   321             for(short i = 0; i < size; i++) {
       
   322                 if (val <= table[i]) { return i; }
       
   323             }
       
   324             return size;
       
   325         }
       
   326 
       
   327         /**
       
   328          * Note that this won't actually read anything; must read in
       
   329          * two-byte units.
       
   330          */
       
   331         public int read() throws IOException {
       
   332             byte[] b = new byte[1];
       
   333             if (read(b, 0, b.length) == 1) {
       
   334                 return b[1] & 0xFF;
       
   335             }
       
   336             return -1;
       
   337         }
       
   338 
       
   339         public int read(byte[] b) throws IOException {
       
   340             return read(b, 0, b.length);
       
   341         }
       
   342 
       
   343         public int read(byte[] b, int off, int len) throws IOException {
       
   344             // don't read fractional frames
       
   345             if( len%frameSize != 0 ) {
       
   346                 len -= (len%frameSize);
       
   347             }
       
   348             if (encode) {
       
   349                 short BIAS = 0x84;
       
   350                 short mask;
       
   351                 short seg;
       
   352                 int i;
       
   353 
       
   354                 short sample;
       
   355                 byte enc;
       
   356 
       
   357                 int readCount = 0;
       
   358                 int currentPos = off;
       
   359                 int readLeft = len*2;
       
   360                 int readLen = ( (readLeft>tempBufferSize) ? tempBufferSize : readLeft );
       
   361 
       
   362                 while ((readCount = super.read(tempBuffer,0,readLen))>0) {
       
   363                     for(i = 0; i < readCount; i+=2) {
       
   364                         /* Get the sample from the tempBuffer */
       
   365                         sample = (short)(( (tempBuffer[i + highByte]) << 8) & 0xFF00);
       
   366                         sample |= (short)( (short) (tempBuffer[i + lowByte]) & 0xFF);
       
   367 
       
   368                         /* Get the sign and the magnitude of the value. */
       
   369                         if(sample < 0) {
       
   370                             sample = (short) (BIAS - sample);
       
   371                             mask = 0x7F;
       
   372                         } else {
       
   373                             sample += BIAS;
       
   374                             mask = 0xFF;
       
   375                         }
       
   376                         /* Convert the scaled magnitude to segment number. */
       
   377                         seg = search(sample, seg_end, (short) 8);
       
   378                         /*
       
   379                          * Combine the sign, segment, quantization bits;
       
   380                          * and complement the code word.
       
   381                          */
       
   382                         if (seg >= 8) {  /* out of range, return maximum value. */
       
   383                             enc = (byte) (0x7F ^ mask);
       
   384                         } else {
       
   385                             enc = (byte) ((seg << 4) | ((sample >> (seg+3)) & 0xF));
       
   386                             enc ^= mask;
       
   387                         }
       
   388                         /* Now put the encoded sample where it belongs */
       
   389                         b[currentPos] = enc;
       
   390                         currentPos++;
       
   391                     }
       
   392                     /* And update pointers and counters for next iteration */
       
   393                     readLeft -= readCount;
       
   394                     readLen = ( (readLeft>tempBufferSize) ? tempBufferSize : readLeft );
       
   395                 }
       
   396                 if( currentPos==off && readCount<0 ) {  // EOF or error on read
       
   397                     return readCount;
       
   398                 }
       
   399                 return (currentPos - off);  /* Number of bytes written to new buffer */
       
   400             } else {
       
   401                 int i;
       
   402                 int readLen = len/2;
       
   403                 int readOffset = off + len/2;
       
   404                 int readCount = super.read(b, readOffset, readLen);
       
   405 
       
   406                 if(readCount<0) {               // EOF or error
       
   407                     return readCount;
       
   408                 }
       
   409                 for (i = off; i < (off + (readCount*2)); i+=2) {
       
   410                     b[i]        = (byte)tabByte1[b[readOffset] & 0xFF];
       
   411                     b[i+1]      = (byte)tabByte2[b[readOffset] & 0xFF];
       
   412                     readOffset++;
       
   413                 }
       
   414                 return (i - off);
       
   415             }
       
   416         }
       
   417     } // end class UlawCodecStream
       
   418 
       
   419 } // end class ULAW