Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]
    1   /*
    2    * Copyright (c) 1999, 2007, Oracle and/or its affiliates. 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.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * 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

Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]