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