/** * 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.data; import java.io.DataInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import marytts.util.io.General; /** * EST Track file reader * * This class interpretes a DataInputStream as an EST_Track file: it loads the whole track data in memory, and provides access * methods to reach each individual frame or each individual track value. * */ public class ESTTrackReader { private int numFrames; private int numChannels; private float[] times; private float[][] frames; private boolean isBigEndian = false; private boolean isBinary = false; /****************/ /* CONSTRUCTORS */ /****************/ /** * Constructor from an already open DataInputStream * * @param dis * DataInputStream to read the EST_Track from * */ public ESTTrackReader(DataInputStream dis) { loadHeaderAndData(dis); } /** * Constructor from a file name * * @param fileName * the name of the file to read the EST_Track from * */ public ESTTrackReader(String fileName) { try { /* Open the file */ FileInputStream fis = new FileInputStream(fileName); /* Stick the file to a DataInputStream to allow easy reading of primitive classes (numbers) */ DataInputStream dis = new DataInputStream(fis); /* Parse the header and load the data */ loadHeaderAndData(dis); /* Close the file */ fis.close(); } catch (FileNotFoundException e) { throw new Error("EST track file [" + fileName + "] was not found."); } catch (SecurityException e) { throw new Error("You do not have read access to the file [" + fileName + "]."); } catch (IOException e) { throw new Error("IO Exception caught when closing file [" + fileName + "]: " + e.getMessage()); } } /*****************/ /* OTHER METHODS */ /*****************/ /** * Parse the EST header and load the track data * * @param dis * DataInputStream to read from * * @throws IOException * on ill-formatted input */ private void loadHeaderAndData(DataInputStream dis) { try { if (!General.readWord(dis).equals("EST_File") || !General.readWord(dis).equals("Track")) { throw new Error("The given data input stream is not an EST Track file."); } // Read Header String token = General.readWord(dis); while (!token.equals("EST_Header_End")) { if (token.equals("DataType")) { if (General.readWord(dis).equals("binary")) { isBinary = true; } else { isBinary = false; } } else if (token.equals("ByteOrder")) { if (General.readWord(dis).equals("10")) { isBigEndian = true; } else { isBigEndian = false; } } else if (token.equals("NumFrames")) { numFrames = Integer.parseInt(General.readWord(dis)); } else if (token.equals("NumChannels")) { numChannels = Integer.parseInt(General.readWord(dis)); } // Ignore all other content in header token = General.readWord(dis); } /* Prepare the storage for the data... */ times = new float[numFrames]; frames = new float[numFrames][numChannels]; /* ... then load it. */ if (isBinary) { loadBinaryData(dis); } else { loadTextData(dis); } } /* Verify if everything went OK during the reading of the DataInputStream */ catch (IOException ioe) { throw new Error("IO Exception while parsing EST Track file: " + ioe.getMessage()); } } /* End of loadHeaderAndData() */ /** * load the data section of the file as ascii text * * @param dis * DataInputStream to read from * * @throws IOException * on ill-formatted input */ private void loadTextData(DataInputStream dis) throws IOException { for (int f = 0; f < numFrames; f++) { times[f] = Float.parseFloat(General.readWord(dis)); General.readWord(dis); // can be only 1 for (int c = 0; c < numChannels; c++) { frames[f][c] = Float.parseFloat(General.readWord(dis)); } } } /** * load the data section of the file as ascii text * * @param dis * DataInputStream to read from * * @throws IOException * on ill-formatted input */ private void loadBinaryData(DataInputStream dis) throws IOException { for (int f = 0; f < numFrames; f++) { times[f] = General.readFloat(dis, isBigEndian); // Ignore the 'breaks' field General.readFloat(dis, isBigEndian); for (int c = 0; c < numChannels; c++) { frames[f][c] = General.readFloat(dis, isBigEndian); } } } /** * Get the number of frames in this track * * @return number of frames in this track */ public int getNumFrames() { return numFrames; } /** * Get the number of channels in this track * * @return number of channels in this track */ public int getNumChannels() { return numChannels; } /** * Get the times associated with this track * * @return an array of times associated with this track */ public float[] getTimes() { return times; } /** * Get the frames associated with this track * * @return an array of frames associated with this track */ public float[][] getFrames() { return frames; } /** * Get an individual time associated with this track * * @param index * index of time to get * * @return time value at given index */ public float getTime(int index) { return times[index]; } /** * Returns the endianness of the file * * @return false if little endian (Intel), true if big endian (PowerPC, SPARC) */ public boolean isBigEndian() { return isBigEndian; } /** * Returns the mode of the file (ascii or binary) * * @return false if ascii text, true if binary */ public boolean isBinary() { return isBinary; } /** * Internal time pointer for the getClosestTime(double) method. */ private int timeIdx = 0; /** * Get the frame time which is closest to a certain time specification. Time specifications falling after the last frame * return the position of the last frame. * * @param seconds * A time point, in seconds. * @return (seconds - t1)<(t2 - seconds) ? t1:t2 */ public float getClosestTime(double seconds) { /* Obvious conditions */ if (seconds < 0.0) return (0.0f); if (seconds > getTimeSpan()) return (getTimeSpan()); /* If the internal pointer is after the requested time, rewind */ if (getTime(timeIdx) > seconds) timeIdx = 0; float t1 = 0.0f; float t2 = getTime(timeIdx); /* Advance the internal time pointer until the requested time is crossed */ while ((t2 < seconds) && (timeIdx < numFrames)) { timeIdx++; t1 = t2; t2 = getTime(timeIdx); } /* Find and return the closest time */ return ((seconds - t1) < (t2 - seconds) ? t1 : t2); } /** * Get the time associated with the last frame * * @return time value of the last frame */ public float getTimeSpan() { return times[numFrames - 1]; } /** * Get an individual frame * * @param i * index of frame * * @return the frame */ public float[] getFrame(int i) { return frames[i]; } /** * Get an individual frame entry * * @param i * index of frame * @param j * index into frame * * @return the frame entry in frame <code>i</code> at index <code>j</code> */ public float getFrameEntry(int i, int j) { return frames[i][j]; } /** * Get the max and the min over the whole file * * @return a vector of 2 float values in the order [min,max]. * */ public float[] getMinMax() { /* Initialize */ float min = getFrameEntry(0, 0); float max = min; float val; /* Browse the values */ for (int f = 0; f < numFrames; f++) { for (int c = 0; c < numChannels; c++) { val = frames[f][c]; if (val < min) { min = val; } ; if (val > max) { max = val; } ; } } /* Return the result in a float vector */ float[] result = new float[2]; // Resulting vector, returned as [min,max,range] result[0] = min; result[1] = max; return result; } /** * Get the max and the min over the whole file, excluding the first column (which can be the energy in the EST LPCs) * * @return a vector of 2 float values in the order [min,max]. * */ public float[] getMinMaxNo1st() { /* Initialize */ float min = getFrameEntry(0, 1); float max = min; float val; /* Browse the values */ for (int f = 0; f < numFrames; f++) { for (int c = 1; c < numChannels; c++) { val = frames[f][c]; if (val < min) { min = val; } ; if (val > max) { max = val; } ; } } /* Return the result in a float vector */ float[] result = new float[2]; // Resulting vector, returned as [min,max,range] result[0] = min; result[1] = max; return result; } }