/** * Portions Copyright 2006 DFKI GmbH. * Portions Copyright 2001 Sun Microsystems, Inc. * Portions Copyright 1999-2001 Language Technologies Institute, * Carnegie Mellon University. * All Rights Reserved. Use is subject to license terms. * * Permission is hereby granted, free of charge, to use and distribute * this software and its documentation without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of this work, and to * permit persons to whom this work is furnished to do so, subject to * the following conditions: * * 1. The code must retain the above copyright notice, this list of * conditions and the following disclaimer. * 2. Any modifications must be clearly marked as such. * 3. Original authors' names are not deleted. * 4. The authors' names are not used to endorse or promote products * derived from this software without specific prior written * permission. * * DFKI GMBH AND THE CONTRIBUTORS TO THIS WORK DISCLAIM ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DFKI GMBH NOR THE * CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF * THIS SOFTWARE. */ package marytts.util.io; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; /** * This class is for general purpose functions such as reading and writing from files, or converting formats of numbers. * * @author Sacha K. */ public class General { /** * Reads the next word (text separated by whitespace) from the given stream * * @param dis * the input stream * * @return the next word * * @throws IOException * on error */ public static String readWord(DataInputStream dis) throws IOException { StringBuilder sb = new StringBuilder(); char c; // skip leading whitespace do { c = readChar(dis); } while (Character.isWhitespace(c)); // read the word do { sb.append(c); c = readChar(dis); } while (!Character.isWhitespace(c)); return sb.toString(); } /** * Reads a single char from the stream * * @param dis * the stream to read * @return the next character on the stream * * @throws IOException * if an error occurs */ public static char readChar(DataInputStream dis) throws IOException { return (char) dis.readByte(); } /** * Reads a given number of chars from the stream * * @param dis * the stream to read * @param num * the number of chars to read * @return a character array containing the next <code>num</code> in the stream * * @throws IOException * if an error occurs */ public static char[] readChars(DataInputStream dis, int num) throws IOException { char[] carray = new char[num]; for (int i = 0; i < num; i++) { carray[i] = readChar(dis); } return carray; } /** * Read a float from the input stream, byte-swapping as necessary * * @param dis * the inputstream * @param isBigEndian * whether or not the data being read in is in big endian format. * * @return a floating pint value * * @throws IOException * on error */ public static float readFloat(DataInputStream dis, boolean isBigEndian) throws IOException { float val; if (!isBigEndian) { val = readLittleEndianFloat(dis); } else { val = dis.readFloat(); } return val; } /** * Write a float from the output stream, byte-swapping as necessary * * @param dos * the outputstream * @param isBigEndian * whether or not the data being read in is in big endian format. * @param val * the floating point value to write * * @throws IOException * on error */ public static void writeFloat(DataOutputStream dos, boolean isBigEndian, float val) throws IOException { if (!isBigEndian) { writeLittleEndianFloat(dos, val); } else { dos.writeFloat(val); } } /** * Reads the next float from the given DataInputStream, where the data is in little endian. * * @param dataStream * the DataInputStream to read from * @throws IOException * IOException * @return a float */ public static float readLittleEndianFloat(DataInputStream dataStream) throws IOException { return Float.intBitsToFloat(readLittleEndianInt(dataStream)); } /** * Writes a float to the given DataOutputStream, where the data is in little endian. * * @param dataStream * the DataOutputStream to write to. * @param val * The float value to write. * @throws IOException * IOException */ public static void writeLittleEndianFloat(DataOutputStream dataStream, float val) throws IOException { writeLittleEndianInt(dataStream, Float.floatToRawIntBits(val)); } /** * Read an integer from the input stream, byte-swapping as necessary * * @param dis * the inputstream * @param isBigEndian * whether or not the data being read in is in big endian format. * * @return an integer value * * @throws IOException * on error */ public static int readInt(DataInputStream dis, boolean isBigEndian) throws IOException { if (!isBigEndian) { return readLittleEndianInt(dis); } else { return dis.readInt(); } } /** * Writes an integer to the output stream, byte-swapping as necessary * * @param dis * the outputstream. * @param isBigEndian * whether or not the data being read in is in big endian format. * @param val * the integer value to write. * * @throws IOException * on error */ public static void writeInt(DataOutputStream dis, boolean isBigEndian, int val) throws IOException { if (!isBigEndian) { writeLittleEndianInt(dis, val); } else { dis.writeInt(val); } } /** * Reads the next little-endian integer from the given DataInputStream. * * @param dataStream * the DataInputStream to read from * @throws IOException * IOException * @return an integer */ public static int readLittleEndianInt(DataInputStream dataStream) throws IOException { int bits = 0x00000000; for (int shift = 0; shift < 32; shift += 8) { int byteRead = (0x000000ff & dataStream.readByte()); bits |= (byteRead << shift); } return bits; } /** * Writes a little-endian integer to the given DataOutputStream. * * @param dataStream * the DataOutputStream to write to * @param val * the integer value to write * * @throws IOException * on error */ public static void writeLittleEndianInt(DataOutputStream dataStream, int val) throws IOException { int mask = 0x000000ff; for (int shift = 0; shift < 32; shift += 8) { dataStream.writeByte(mask & (val >> shift)); } } /** * Read a short from the input stream, byte-swapping as necessary * * @param dis * the inputstream * @param isBigEndian * whether or not the data being read in is in big endian format. * * @return an integer value * * @throws IOException * on error */ public static short readShort(DataInputStream dis, boolean isBigEndian) throws IOException { if (!isBigEndian) { return readLittleEndianShort(dis); } else { return dis.readShort(); } } /** * Reads the next little-endian short from the given DataInputStream. * * @param dis * the DataInputStream to read from * @throws IOException * IOException * @return a short */ public static short readLittleEndianShort(DataInputStream dis) throws IOException { short bits = (short) (0x0000ff & dis.readByte()); bits |= (((short) (0x0000ff & dis.readByte())) << 8); return bits; } /** * Convert a short to ulaw format * * @param sample * the short to convert * * @return a short containing an unsigned 8-bit quantity representing the ulaw */ public static byte shortToUlaw(short sample) { final int[] exp_lut = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }; int sign, exponent, mantissa; short ulawbyte; final short CLIP = 32635; final short BIAS = 0x0084; /* Get the sample into sign-magnitude. */ sign = (sample >> 8) & 0x80; /* set aside the sign */ if (sign != 0) { sample = (short) -sample; /* get magnitude */ } if (sample > CLIP) sample = CLIP; /* clip the magnitude */ /* Convert from 16 bit linear to ulaw. */ sample = (short) (sample + BIAS); exponent = exp_lut[(sample >> 7) & 0xFF]; mantissa = (sample >> (exponent + 3)) & 0x0F; ulawbyte = (short) ((~(sign | (exponent << 4) | mantissa)) & 0x00FF); if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */ // Now ulawbyte is an unsigned 8-bit entity. // Return as a (signed) byte: return (byte) (ulawbyte - 128); } /** * Convert a ulaw format to short * * @param ulaw * a (signed) byte which, after converting into a short and adding 128, will be an unsigned 8-but quantity * representing a ulaw * * @return the short equivalent of the ulaw */ public static short ulawToShort(byte ulaw) { short ulawbyte = (short) (ulaw + 128); final int[] exp_lut = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 }; int sign, exponent, mantissa; short sample; ulawbyte = (short) (ulawbyte & 0x00FF); ulawbyte = (short) (~ulawbyte); sign = (ulawbyte & ((short) 0x80)); exponent = (int) ((ulawbyte & (short) 0x00FF) >> 4) & 0x07; mantissa = ulawbyte & (short) 0x0F; sample = (short) (exp_lut[exponent] + (mantissa << (exponent + 3))); if (sign != 0) sample = (short) (-sample); return sample; } /** * Convert an array from short to ulaw. * * @param samples * an array in linear representation * @return an array in ulaw representation. * @see #shortToUlaw(short) */ public static byte[] shortToUlaw(short[] samples) { if (samples == null) return null; byte[] ulaw = new byte[samples.length]; for (int i = 0; i < samples.length; i++) { ulaw[i] = shortToUlaw(samples[i]); } return ulaw; } /** * Convert an array from ulaw to short. * * @param ulaw * an array in ulaw representation * @return an array in linear representation. * @see #ulawToShort(byte) */ public static short[] ulawToShort(byte[] ulaw) { if (ulaw == null) return null; short[] samples = new short[ulaw.length]; for (int i = 0; i < ulaw.length; i++) { samples[i] = ulawToShort(ulaw[i]); } return samples; } /** * Print a float type's internal bit representation in hex * * @param f * the float to print * * @return a string containing the hex value of <code>f</code> */ public static String hex(float f) { return Integer.toHexString(Float.floatToIntBits(f)); } /** * Quantize a float variable over the 16bits signed short range * * @param f * the float to quantize * @param fMin * the minimum possible value for variable f * @param fRange * the possible range for variable f * * @return the 16bits signed codeword, returned as a signed short * * */ public static short quantize(float f, float fMin, float fRange) { return ((short) (((double) f - (double) fMin) * 65535.0 / ((double) fRange) - 32768.0)); } /** * Quantize an array of floats over the 16bits signed short range * * @param f * the array of floats to quantize * @param fMin * the minimum possible value for variable f * @param fRange * the possible range for variable f * * @return an array of 16bits signed codewords, returned as signed shorts * * */ public static short[] quantize(float[] f, float fMin, float fRange) { int len = f.length; short[] ret = new short[len]; for (int i = 0; i < len; i++) ret[i] = quantize(f[i], fMin, fRange); return (ret); } /** * Unquantize a 16bits signed short over a float range * * @param s * the 16bits signed codeword * @param fMin * the minimum possible value for variable f * @param fRange * the possible range for variable f * * @return the corresponding float value * * */ public static float unQuantize(short s, float fMin, float fRange) { return ((float) (((double) (s) + 32768.0) * (double) fRange / 65535.0 - (double) fMin)); } /** * Unquantize an array of 16bits signed shorts over a float range * * @param s * the array of 16bits signed codewords * @param fMin * the minimum possible value for variable f * @param fRange * the possible range for variable f * * @return the corresponding array of float values * * */ public static float[] unQuantize(short[] s, float fMin, float fRange) { int len = s.length; float[] ret = new float[len]; for (int i = 0; i < len; i++) ret[i] = unQuantize(s[i], fMin, fRange); return (ret); } /** * A general process launcher for the various tasks * * @param cmdLine * the command line to be launched. * @param task * a task tag for error messages, such as "Pitchmarks" or "LPC". * @param baseName * basename of the file currently processed, for error messages. */ public static void launchProc(String cmdLine, String task, String baseName) { Process proc = null; String line = null; // String[] cmd = null; // Java 5.0 compliant code try { /* Java 5.0 compliant code below. */ /* Hook the command line to the process builder: */ /* * cmd = cmdLine.split( " " ); pb.command( cmd ); /* /* Launch the process: */ /* proc = pb.start(); */ /* Java 1.0 equivalent: */ proc = Runtime.getRuntime().exec(cmdLine); /* Collect stdout and send it to System.out: */ InputStream procStdOut = proc.getInputStream(); InputStream procStdErr = proc.getErrorStream(); StreamLogger stdOutLogger = new StreamLogger(procStdOut, System.out); StreamLogger stdErrLogger = new StreamLogger(procStdErr, System.err); stdOutLogger.start(); stdErrLogger.start(); try { stdOutLogger.join(); stdErrLogger.join(); } catch (InterruptedException e) { e.printStackTrace(); } /* Wait and check the exit value */ proc.waitFor(); if (proc.exitValue() != 0) { throw new RuntimeException(task + " computation failed on file [" + baseName + "]!\n" + "Command line was: [" + cmdLine + "]."); } } catch (IOException e) { throw new RuntimeException(task + " computation provoked an IOException on file [" + baseName + "].", e); } catch (InterruptedException e) { throw new RuntimeException(task + " computation interrupted on file [" + baseName + "].", e); } } /** * A general process launcher for the various tasks but using an intermediate batch file * * @param cmdLine * the command line to be launched. * @param task * a task tag for error messages, such as "Pitchmarks" or "LPC". * @param filedir * filedir of the file currently processed, for error messages and for creating a temporal batch file. */ public static void launchBatchProc(String cmdLine, String task, String filedir) { Process proc = null; Process proctmp = null; BufferedReader procStdout = null; String line = null; String tmpFile = filedir + "tmp.bat"; System.out.println("Running: " + cmdLine); // String[] cmd = null; // Java 5.0 compliant code try { FileWriter tmp = new FileWriter(tmpFile); tmp.write(cmdLine); tmp.close(); /* make it executable... */ proctmp = Runtime.getRuntime().exec("chmod +x " + tmpFile); proctmp.waitFor(); if (proctmp.exitValue() != 0) { BufferedReader errReader = new BufferedReader(new InputStreamReader(proctmp.getErrorStream())); while ((line = errReader.readLine()) != null) { System.err.println("ERR> " + line); } errReader.close(); throw new RuntimeException(task + " computation failed on file [" + filedir + "]!\n" + "Command line was: [chmod +x " + tmpFile + "]."); } /* Java 5.0 compliant code below. */ /* Hook the command line to the process builder: */ /* * cmd = cmdLine.split( " " ); pb.command( cmd ); /* /* Launch the process: */ /* proc = pb.start(); */ /* Java 1.0 equivalent: */ proc = Runtime.getRuntime().exec(tmpFile); InputStream procStdOut = proc.getInputStream(); InputStream procStdErr = proc.getErrorStream(); StreamLogger stdOutLogger = new StreamLogger(procStdOut, System.out); StreamLogger stdErrLogger = new StreamLogger(procStdErr, System.err); stdOutLogger.start(); stdErrLogger.start(); try { stdOutLogger.join(); stdErrLogger.join(); } catch (InterruptedException e) { e.printStackTrace(); } /* Wait and check the exit value */ proc.waitFor(); if (proc.exitValue() != 0) { BufferedReader errReader = new BufferedReader(new InputStreamReader(proc.getErrorStream())); while ((line = errReader.readLine()) != null) { System.err.println("ERR> " + line); } errReader.close(); throw new RuntimeException(task + " computation failed on file [" + filedir + "]!\n" + "Command line was: [" + cmdLine + "]."); } // Delete tmp.bat if created File batchFile = new File(tmpFile); if (batchFile.exists()) { batchFile.delete(); } } catch (IOException e) { throw new RuntimeException(task + " computation provoked an IOException on file [" + filedir + "].", e); } catch (InterruptedException e) { throw new RuntimeException(task + " computation interrupted on file [" + filedir + "].", e); } } }