Home | History | Annotate | Download | only in srec
      1 /*
      2  * ---------------------------------------------------------------------------
      3  * UlawEncoderInputStream.java
      4  *
      5  * Copyright 2008 Nuance Communciations, Inc.
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the 'License'); you may not
      8  * use this file except in compliance with the License.
      9  *
     10  * You may obtain a copy of the License at
     11  * http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
     15  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     16  * License for the specific language governing permissions and limitations under
     17  * the License.
     18  *
     19  * ---------------------------------------------------------------------------
     20  */
     21 
     22 package android.speech.srec;
     23 
     24 import java.io.IOException;
     25 import java.io.InputStream;
     26 
     27 /**
     28  * InputStream which transforms 16 bit pcm data to ulaw data.
     29  *
     30  * Not yet ready to be supported, so
     31  * @hide
     32  */
     33 public final class UlawEncoderInputStream extends InputStream {
     34     private final static String TAG = "UlawEncoderInputStream";
     35 
     36     private final static int MAX_ULAW = 8192;
     37     private final static int SCALE_BITS = 16;
     38 
     39     private InputStream mIn;
     40 
     41     private int mMax = 0;
     42 
     43     private final byte[] mBuf = new byte[1024];
     44     private int mBufCount = 0; // should be 0 or 1
     45 
     46     private final byte[] mOneByte = new byte[1];
     47 
     48 
     49     public static void encode(byte[] pcmBuf, int pcmOffset,
     50             byte[] ulawBuf, int ulawOffset, int length, int max) {
     51 
     52         // from  'ulaw' in wikipedia
     53         // +8191 to +8159                          0x80
     54         // +8158 to +4063 in 16 intervals of 256   0x80 + interval number
     55         // +4062 to +2015 in 16 intervals of 128   0x90 + interval number
     56         // +2014 to  +991 in 16 intervals of  64   0xA0 + interval number
     57         //  +990 to  +479 in 16 intervals of  32   0xB0 + interval number
     58         //  +478 to  +223 in 16 intervals of  16   0xC0 + interval number
     59         //  +222 to   +95 in 16 intervals of   8   0xD0 + interval number
     60         //   +94 to   +31 in 16 intervals of   4   0xE0 + interval number
     61         //   +30 to    +1 in 15 intervals of   2   0xF0 + interval number
     62         //     0                                   0xFF
     63 
     64         //    -1                                   0x7F
     65         //   -31 to    -2 in 15 intervals of   2   0x70 + interval number
     66         //   -95 to   -32 in 16 intervals of   4   0x60 + interval number
     67         //  -223 to   -96 in 16 intervals of   8   0x50 + interval number
     68         //  -479 to  -224 in 16 intervals of  16   0x40 + interval number
     69         //  -991 to  -480 in 16 intervals of  32   0x30 + interval number
     70         // -2015 to  -992 in 16 intervals of  64   0x20 + interval number
     71         // -4063 to -2016 in 16 intervals of 128   0x10 + interval number
     72         // -8159 to -4064 in 16 intervals of 256   0x00 + interval number
     73         // -8192 to -8160                          0x00
     74 
     75         // set scale factors
     76         if (max <= 0) max = MAX_ULAW;
     77 
     78         int coef = MAX_ULAW * (1 << SCALE_BITS) / max;
     79 
     80         for (int i = 0; i < length; i++) {
     81             int pcm = (0xff & pcmBuf[pcmOffset++]) + (pcmBuf[pcmOffset++] << 8);
     82             pcm = (pcm * coef) >> SCALE_BITS;
     83 
     84             int ulaw;
     85             if (pcm >= 0) {
     86                 ulaw = pcm <= 0 ? 0xff :
     87                         pcm <=   30 ? 0xf0 + ((  30 - pcm) >> 1) :
     88                         pcm <=   94 ? 0xe0 + ((  94 - pcm) >> 2) :
     89                         pcm <=  222 ? 0xd0 + (( 222 - pcm) >> 3) :
     90                         pcm <=  478 ? 0xc0 + (( 478 - pcm) >> 4) :
     91                         pcm <=  990 ? 0xb0 + (( 990 - pcm) >> 5) :
     92                         pcm <= 2014 ? 0xa0 + ((2014 - pcm) >> 6) :
     93                         pcm <= 4062 ? 0x90 + ((4062 - pcm) >> 7) :
     94                         pcm <= 8158 ? 0x80 + ((8158 - pcm) >> 8) :
     95                         0x80;
     96             } else {
     97                 ulaw = -1 <= pcm ? 0x7f :
     98                           -31 <= pcm ? 0x70 + ((pcm -   -31) >> 1) :
     99                           -95 <= pcm ? 0x60 + ((pcm -   -95) >> 2) :
    100                          -223 <= pcm ? 0x50 + ((pcm -  -223) >> 3) :
    101                          -479 <= pcm ? 0x40 + ((pcm -  -479) >> 4) :
    102                          -991 <= pcm ? 0x30 + ((pcm -  -991) >> 5) :
    103                         -2015 <= pcm ? 0x20 + ((pcm - -2015) >> 6) :
    104                         -4063 <= pcm ? 0x10 + ((pcm - -4063) >> 7) :
    105                         -8159 <= pcm ? 0x00 + ((pcm - -8159) >> 8) :
    106                         0x00;
    107             }
    108             ulawBuf[ulawOffset++] = (byte)ulaw;
    109         }
    110     }
    111 
    112     /**
    113      * Compute the maximum of the absolute value of the pcm samples.
    114      * The return value can be used to set ulaw encoder scaling.
    115      * @param pcmBuf array containing 16 bit pcm data.
    116      * @param offset offset of start of 16 bit pcm data.
    117      * @param length number of pcm samples (not number of input bytes)
    118      * @return maximum abs of pcm data values
    119      */
    120     public static int maxAbsPcm(byte[] pcmBuf, int offset, int length) {
    121         int max = 0;
    122         for (int i = 0; i < length; i++) {
    123             int pcm = (0xff & pcmBuf[offset++]) + (pcmBuf[offset++] << 8);
    124             if (pcm < 0) pcm = -pcm;
    125             if (pcm > max) max = pcm;
    126         }
    127         return max;
    128     }
    129 
    130     /**
    131      * Create an InputStream which takes 16 bit pcm data and produces ulaw data.
    132      * @param in InputStream containing 16 bit pcm data.
    133      * @param max pcm value corresponding to maximum ulaw value.
    134      */
    135     public UlawEncoderInputStream(InputStream in, int max) {
    136         mIn = in;
    137         mMax = max;
    138     }
    139 
    140     @Override
    141     public int read(byte[] buf, int offset, int length) throws IOException {
    142         if (mIn == null) throw new IllegalStateException("not open");
    143 
    144         // return at least one byte, but try to fill 'length'
    145         while (mBufCount < 2) {
    146             int n = mIn.read(mBuf, mBufCount, Math.min(length * 2, mBuf.length - mBufCount));
    147             if (n == -1) return -1;
    148             mBufCount += n;
    149         }
    150 
    151         // compand data
    152         int n = Math.min(mBufCount / 2, length);
    153         encode(mBuf, 0, buf, offset, n, mMax);
    154 
    155         // move data to bottom of mBuf
    156         mBufCount -= n * 2;
    157         for (int i = 0; i < mBufCount; i++) mBuf[i] = mBuf[i + n * 2];
    158 
    159         return n;
    160     }
    161 
    162     @Override
    163     public int read(byte[] buf) throws IOException {
    164         return read(buf, 0, buf.length);
    165     }
    166 
    167     @Override
    168     public int read() throws IOException {
    169         int n = read(mOneByte, 0, 1);
    170         if (n == -1) return -1;
    171         return 0xff & (int)mOneByte[0];
    172     }
    173 
    174     @Override
    175     public void close() throws IOException {
    176         if (mIn != null) {
    177             InputStream in = mIn;
    178             mIn = null;
    179             in.close();
    180         }
    181     }
    182 
    183     @Override
    184     public int available() throws IOException {
    185         return (mIn.available() + mBufCount) / 2;
    186     }
    187 }
    188