19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ---------------------------------------------------------------------------
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * UlawEncoderInputStream.java
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright 2008 Nuance Communciations, Inc.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the 'License'); you may not
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * use this file except in compliance with the License.
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * License for the specific language governing permissions and limitations under
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the License.
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ---------------------------------------------------------------------------
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.speech.srec;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.InputStream;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * InputStream which transforms 16 bit pcm data to ulaw data.
29935ae463d495d41155e27feb849768ad2b8b16dbDianne Hackborn *
30935ae463d495d41155e27feb849768ad2b8b16dbDianne Hackborn * Not yet ready to be supported, so
31935ae463d495d41155e27feb849768ad2b8b16dbDianne Hackborn * @hide
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic final class UlawEncoderInputStream extends InputStream {
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static String TAG = "UlawEncoderInputStream";
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static int MAX_ULAW = 8192;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static int SCALE_BITS = 16;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private InputStream mIn;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mMax = 0;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final byte[] mBuf = new byte[1024];
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mBufCount = 0; // should be 0 or 1
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final byte[] mOneByte = new byte[1];
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void encode(byte[] pcmBuf, int pcmOffset,
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            byte[] ulawBuf, int ulawOffset, int length, int max) {
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // from  'ulaw' in wikipedia
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // +8191 to +8159                          0x80
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // +8158 to +4063 in 16 intervals of 256   0x80 + interval number
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // +4062 to +2015 in 16 intervals of 128   0x90 + interval number
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // +2014 to  +991 in 16 intervals of  64   0xA0 + interval number
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //  +990 to  +479 in 16 intervals of  32   0xB0 + interval number
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //  +478 to  +223 in 16 intervals of  16   0xC0 + interval number
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //  +222 to   +95 in 16 intervals of   8   0xD0 + interval number
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //   +94 to   +31 in 16 intervals of   4   0xE0 + interval number
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //   +30 to    +1 in 15 intervals of   2   0xF0 + interval number
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //     0                                   0xFF
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //    -1                                   0x7F
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //   -31 to    -2 in 15 intervals of   2   0x70 + interval number
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //   -95 to   -32 in 16 intervals of   4   0x60 + interval number
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //  -223 to   -96 in 16 intervals of   8   0x50 + interval number
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //  -479 to  -224 in 16 intervals of  16   0x40 + interval number
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //  -991 to  -480 in 16 intervals of  32   0x30 + interval number
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // -2015 to  -992 in 16 intervals of  64   0x20 + interval number
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // -4063 to -2016 in 16 intervals of 128   0x10 + interval number
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // -8159 to -4064 in 16 intervals of 256   0x00 + interval number
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // -8192 to -8160                          0x00
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // set scale factors
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (max <= 0) max = MAX_ULAW;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int coef = MAX_ULAW * (1 << SCALE_BITS) / max;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < length; i++) {
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int pcm = (0xff & pcmBuf[pcmOffset++]) + (pcmBuf[pcmOffset++] << 8);
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pcm = (pcm * coef) >> SCALE_BITS;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int ulaw;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (pcm >= 0) {
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ulaw = pcm <= 0 ? 0xff :
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        pcm <=   30 ? 0xf0 + ((  30 - pcm) >> 1) :
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        pcm <=   94 ? 0xe0 + ((  94 - pcm) >> 2) :
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        pcm <=  222 ? 0xd0 + (( 222 - pcm) >> 3) :
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        pcm <=  478 ? 0xc0 + (( 478 - pcm) >> 4) :
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        pcm <=  990 ? 0xb0 + (( 990 - pcm) >> 5) :
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        pcm <= 2014 ? 0xa0 + ((2014 - pcm) >> 6) :
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        pcm <= 4062 ? 0x90 + ((4062 - pcm) >> 7) :
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        pcm <= 8158 ? 0x80 + ((8158 - pcm) >> 8) :
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        0x80;
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ulaw = -1 <= pcm ? 0x7f :
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          -31 <= pcm ? 0x70 + ((pcm -   -31) >> 1) :
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          -95 <= pcm ? 0x60 + ((pcm -   -95) >> 2) :
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         -223 <= pcm ? 0x50 + ((pcm -  -223) >> 3) :
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         -479 <= pcm ? 0x40 + ((pcm -  -479) >> 4) :
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         -991 <= pcm ? 0x30 + ((pcm -  -991) >> 5) :
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        -2015 <= pcm ? 0x20 + ((pcm - -2015) >> 6) :
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        -4063 <= pcm ? 0x10 + ((pcm - -4063) >> 7) :
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        -8159 <= pcm ? 0x00 + ((pcm - -8159) >> 8) :
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        0x00;
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ulawBuf[ulawOffset++] = (byte)ulaw;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Compute the maximum of the absolute value of the pcm samples.
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The return value can be used to set ulaw encoder scaling.
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param pcmBuf array containing 16 bit pcm data.
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param offset offset of start of 16 bit pcm data.
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param length number of pcm samples (not number of input bytes)
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return maximum abs of pcm data values
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static int maxAbsPcm(byte[] pcmBuf, int offset, int length) {
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int max = 0;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < length; i++) {
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int pcm = (0xff & pcmBuf[offset++]) + (pcmBuf[offset++] << 8);
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (pcm < 0) pcm = -pcm;
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (pcm > max) max = pcm;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return max;
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create an InputStream which takes 16 bit pcm data and produces ulaw data.
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param in InputStream containing 16 bit pcm data.
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param max pcm value corresponding to maximum ulaw value.
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public UlawEncoderInputStream(InputStream in, int max) {
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIn = in;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMax = max;
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int read(byte[] buf, int offset, int length) throws IOException {
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIn == null) throw new IllegalStateException("not open");
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // return at least one byte, but try to fill 'length'
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (mBufCount < 2) {
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int n = mIn.read(mBuf, mBufCount, Math.min(length * 2, mBuf.length - mBufCount));
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (n == -1) return -1;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mBufCount += n;
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // compand data
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int n = Math.min(mBufCount / 2, length);
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        encode(mBuf, 0, buf, offset, n, mMax);
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // move data to bottom of mBuf
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBufCount -= n * 2;
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < mBufCount; i++) mBuf[i] = mBuf[i + n * 2];
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return n;
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int read(byte[] buf) throws IOException {
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return read(buf, 0, buf.length);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int read() throws IOException {
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int n = read(mOneByte, 0, 1);
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (n == -1) return -1;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0xff & (int)mOneByte[0];
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void close() throws IOException {
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIn != null) {
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            InputStream in = mIn;
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mIn = null;
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            in.close();
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int available() throws IOException {
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mIn.available() + mBufCount) / 2;
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
188