WaveHeader.java (8105B)
1 package be.tarsos.dsp.writer; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.OutputStream; 6 7 /** 8 * this source code is copied from : https://android.googlesource.com/platform/frameworks/base.git/+/android-4.3_r2/core/java/android/speech/srec/WaveHeader.java 9 */ 10 /** 11 * This class represents the header of a WAVE format audio file, which usually 12 * have a .wav suffix. The following integer valued fields are contained: 13 * <ul> 14 * <li> format - usually PCM, ALAW or ULAW. 15 * <li> numChannels - 1 for mono, 2 for stereo. 16 * <li> sampleRate - usually 8000, 11025, 16000, 22050, or 44100 hz. 17 * <li> bitsPerSample - usually 16 for PCM, 8 for ALAW, or 8 for ULAW. 18 * <li> numBytes - size of audio data after this header, in bytes. 19 * </ul> 20 * 21 * Not yet ready to be supported, so 22 * @hide 23 */ 24 public class WaveHeader { 25 26 // follows WAVE format in http://ccrma.stanford.edu/courses/422/projects/WaveFormat 27 28 private static final int HEADER_LENGTH = 44; 29 30 /** Indicates PCM format. */ 31 public static final short FORMAT_PCM = 1; 32 /** Indicates ALAW format. */ 33 public static final short FORMAT_ALAW = 6; 34 /** Indicates ULAW format. */ 35 public static final short FORMAT_ULAW = 7; 36 37 private short mFormat; 38 private short mNumChannels; 39 private int mSampleRate; 40 private short mBitsPerSample; 41 private int mNumBytes; 42 43 /** 44 * Construct a WaveHeader, with all fields defaulting to zero. 45 */ 46 public WaveHeader() { 47 } 48 49 /** 50 * Construct a WaveHeader, with fields initialized. 51 * @param format format of audio data, 52 * one of {@link #FORMAT_PCM}, {@link #FORMAT_ULAW}, or {@link #FORMAT_ALAW}. 53 * @param numChannels 1 for mono, 2 for stereo. 54 * @param sampleRate typically 8000, 11025, 16000, 22050, or 44100 hz. 55 * @param bitsPerSample usually 16 for PCM, 8 for ULAW or 8 for ALAW. 56 * @param numBytes size of audio data after this header, in bytes. 57 */ 58 public WaveHeader(short format, short numChannels, int sampleRate, short bitsPerSample, int numBytes) { 59 mFormat = format; 60 mSampleRate = sampleRate; 61 mNumChannels = numChannels; 62 mBitsPerSample = bitsPerSample; 63 mNumBytes = numBytes; 64 } 65 66 /** 67 * Get the format field. 68 * @return format field, 69 * one of {@link #FORMAT_PCM}, {@link #FORMAT_ULAW}, or {@link #FORMAT_ALAW}. 70 */ 71 public short getFormat() { 72 return mFormat; 73 } 74 75 /** 76 * Set the format field. 77 * @param format 78 * one of {@link #FORMAT_PCM}, {@link #FORMAT_ULAW}, or {@link #FORMAT_ALAW}. 79 * @return reference to this WaveHeader instance. 80 */ 81 public WaveHeader setFormat(short format) { 82 mFormat = format; 83 return this; 84 } 85 86 /** 87 * Get the number of channels. 88 * @return number of channels, 1 for mono, 2 for stereo. 89 */ 90 public short getNumChannels() { 91 return mNumChannels; 92 } 93 94 /** 95 * Set the number of channels. 96 * @param numChannels 1 for mono, 2 for stereo. 97 * @return reference to this WaveHeader instance. 98 */ 99 public WaveHeader setNumChannels(short numChannels) { 100 mNumChannels = numChannels; 101 return this; 102 } 103 104 /** 105 * Get the sample rate. 106 * @return sample rate, typically 8000, 11025, 16000, 22050, or 44100 hz. 107 */ 108 public int getSampleRate() { 109 return mSampleRate; 110 } 111 112 /** 113 * Set the sample rate. 114 * @param sampleRate sample rate, typically 8000, 11025, 16000, 22050, or 44100 hz. 115 * @return reference to this WaveHeader instance. 116 */ 117 public WaveHeader setSampleRate(int sampleRate) { 118 mSampleRate = sampleRate; 119 return this; 120 } 121 122 /** 123 * Get the number of bits per sample. 124 * @return number of bits per sample, 125 * usually 16 for PCM, 8 for ULAW or 8 for ALAW. 126 */ 127 public short getBitsPerSample() { 128 return mBitsPerSample; 129 } 130 131 /** 132 * Set the number of bits per sample. 133 * @param bitsPerSample number of bits per sample, 134 * usually 16 for PCM, 8 for ULAW or 8 for ALAW. 135 * @return reference to this WaveHeader instance. 136 */ 137 public WaveHeader setBitsPerSample(short bitsPerSample) { 138 mBitsPerSample = bitsPerSample; 139 return this; 140 } 141 142 /** 143 * Get the size of audio data after this header, in bytes. 144 * @return size of audio data after this header, in bytes. 145 */ 146 public int getNumBytes() { 147 return mNumBytes; 148 } 149 150 /** 151 * Set the size of audio data after this header, in bytes. 152 * @param numBytes size of audio data after this header, in bytes. 153 * @return reference to this WaveHeader instance. 154 */ 155 public WaveHeader setNumBytes(int numBytes) { 156 mNumBytes = numBytes; 157 return this; 158 } 159 160 /** 161 * Read and initialize a WaveHeader. 162 * @param in {@link java.io.InputStream} to read from. 163 * @return number of bytes consumed. 164 * @throws IOException 165 */ 166 public int read(InputStream in) throws IOException { 167 /* RIFF header */ 168 readId(in, "RIFF"); 169 170 readId(in, "WAVE"); 171 172 /* fmt chunk */ 173 readId(in, "fmt "); 174 if (16 != readInt(in)) throw new IOException("fmt chunk length not 16"); 175 mFormat = readShort(in); 176 mNumChannels = readShort(in); 177 mSampleRate = readInt(in); 178 int byteRate = readInt(in); 179 short blockAlign = readShort(in); 180 mBitsPerSample = readShort(in); 181 if (byteRate != mNumChannels * mSampleRate * mBitsPerSample / 8) { 182 throw new IOException("fmt.ByteRate field inconsistent"); 183 } 184 if (blockAlign != mNumChannels * mBitsPerSample / 8) { 185 throw new IOException("fmt.BlockAlign field inconsistent"); 186 } 187 188 /* data chunk */ 189 readId(in, "data"); 190 mNumBytes = readInt(in); 191 192 return HEADER_LENGTH; 193 } 194 195 private static void readId(InputStream in, String id) throws IOException { 196 for (int i = 0; i < id.length(); i++) { 197 if (id.charAt(i) != in.read()) throw new IOException( id + " tag not present"); 198 } 199 } 200 201 private static int readInt(InputStream in) throws IOException { 202 return in.read() | (in.read() << 8) | (in.read() << 16) | (in.read() << 24); 203 } 204 205 private static short readShort(InputStream in) throws IOException { 206 return (short)(in.read() | (in.read() << 8)); 207 } 208 209 /** 210 * Write a WAVE file header. 211 * @param out {@link java.io.OutputStream} to receive the header. 212 * @return number of bytes written. 213 * @throws IOException 214 */ 215 public int write(OutputStream out) throws IOException { 216 /* RIFF header */ 217 writeId(out, "RIFF"); 218 writeInt(out, 36 + mNumBytes); 219 writeId(out, "WAVE"); 220 221 /* fmt chunk */ 222 writeId(out, "fmt "); 223 writeInt(out, 16); 224 writeShort(out, mFormat); 225 writeShort(out, mNumChannels); 226 writeInt(out, mSampleRate); 227 writeInt(out, mNumChannels * mSampleRate * mBitsPerSample / 8); 228 writeShort(out, (short)(mNumChannels * mBitsPerSample / 8)); 229 writeShort(out, mBitsPerSample); 230 231 /* data chunk */ 232 writeId(out, "data"); 233 writeInt(out, mNumBytes); 234 235 return HEADER_LENGTH; 236 } 237 238 private static void writeId(OutputStream out, String id) throws IOException { 239 for (int i = 0; i < id.length(); i++) out.write(id.charAt(i)); 240 } 241 242 private static void writeInt(OutputStream out, int val) throws IOException { 243 out.write(val >> 0); 244 out.write(val >> 8); 245 out.write(val >> 16); 246 out.write(val >> 24); 247 } 248 249 private static void writeShort(OutputStream out, short val) throws IOException { 250 out.write(val >> 0); 251 out.write(val >> 8); 252 } 253 254 @Override 255 public String toString() { 256 return String.format( 257 "WaveHeader format=%d numChannels=%d sampleRate=%d bitsPerSample=%d numBytes=%d", 258 mFormat, mNumChannels, mSampleRate, mBitsPerSample, mNumBytes); 259 } 260 261 }