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 22package android.speech.srec; 23 24import java.io.IOException; 25import 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 */ 33public 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