/** * Copyright 2007 DFKI GmbH. * 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.signalproc.adaptation.prosody; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import marytts.signalproc.analysis.Labels; import marytts.signalproc.analysis.PitchReaderWriter; import marytts.util.math.ArrayUtils; import marytts.util.math.MathUtils; import marytts.util.signal.SignalProcUtils; /** * A basic class that contains prosody modification information and corresponding time instants * * @author oytun.turk * */ public class BasicProsodyModifierParams implements Serializable { public float[] tScales; // Time scale factors public float[] tScalesTimes; // Instants that the time scale factors are effective. // For the time instants in between, linear interpolation is used to estimate corresponding // time scaling factor. public float[] pScales; // Pitch scale factors public float[] pScalesTimes; // Instants that the pitch scale factors are effective. // For the time instants in between, linear interpolation is used to estimate corresponding // pitch scaling factor. public BasicProsodyModifierParams() { // this has no effect: // tScales = null; // tScalesTimes = null; // pScales = null; // pScalesTimes = null; } public BasicProsodyModifierParams(BasicProsodyModifierParams existing) { setTScales(existing.tScales); setTScalesTimes(existing.tScalesTimes); setPScales(existing.pScales); setPScalesTimes(existing.pScalesTimes); } public BasicProsodyModifierParams(float[] tScalesIn, float[] tScalesTimesIn) { this(); setTScales(tScalesIn); setTScalesTimes(tScalesTimesIn); } public BasicProsodyModifierParams(float[] tScalesIn, float[] tScalesTimesIn, float[] pScalesIn, float[] pScalesTimesIn) { this(); setTScales(tScalesIn); setTScalesTimes(tScalesTimesIn); setPScales(pScalesIn); setPScalesTimes(pScalesTimesIn); } // Estimate time and duration scaling factors from source and target labels and pitch contours // This version assumes identical source and target labels public BasicProsodyModifierParams(String sourcePtcFile, String sourceLabelFile, String targetPtcFile, String targetLabelFile, boolean isPitchScale, boolean isTimeScale) throws IOException { PitchReaderWriter f0Src = new PitchReaderWriter(sourcePtcFile); Labels labSrc = new Labels(sourceLabelFile); PitchReaderWriter f0Tgt = new PitchReaderWriter(targetPtcFile); Labels labTgt = new Labels(targetLabelFile); init(f0Src, labSrc, f0Tgt, labTgt, isPitchScale, isTimeScale); } // Estimate time and duration scaling factors from source and target labels and pitch contours // This version assumes identical source and target labels public BasicProsodyModifierParams(PitchReaderWriter f0Src, Labels labSrc, PitchReaderWriter f0Tgt, Labels labTgt, boolean isPitchScale, boolean isTimeScale) { init(f0Src, labSrc, f0Tgt, labTgt, isPitchScale, isTimeScale); } public void init(PitchReaderWriter f0Src, Labels labSrc, PitchReaderWriter f0Tgt, Labels labTgt, boolean isPitchScale, boolean isTimeScale) { int numLabels = 0; if (labSrc != null && labTgt != null && labSrc.items != null && labTgt.items != null) numLabels = Math.min(labSrc.items.length, labTgt.items.length); if (isTimeScale && numLabels > 0) { tScales = new float[numLabels]; tScalesTimes = new float[numLabels]; float tStartSrc = 0.0f; float tStartTgt = 0.0f; for (int i = 0; i < numLabels; i++) { tScales[i] = (float) ((labTgt.items[i].time - tStartTgt) / (labSrc.items[i].time - tStartSrc)); tScalesTimes[i] = (float) (0.5 * (tStartSrc + labSrc.items[i].time)); tStartTgt = (float) labTgt.items[i].time; tStartSrc = (float) labSrc.items[i].time; } } else { setTScales(1.0f); setTScalesTimes(null); } if (isPitchScale) { pScales = new float[f0Src.header.numfrm]; pScalesTimes = new float[f0Src.header.numfrm]; float tStartSrc = 0.0f; float tStartTgt = 0.0f; int labInd; double sourceTime, targetTime; int tgtF0Ind; for (int i = 0; i < f0Src.header.numfrm; i++) { sourceTime = (i * f0Src.header.skipSizeInSeconds + 0.5 * f0Src.header.windowSizeInSeconds); if (labSrc != null && labTgt != null && labSrc.items != null && labTgt.items != null) { labInd = SignalProcUtils.frameIndex2LabelIndex(i, labSrc, f0Src.header.windowSizeInSeconds, f0Src.header.skipSizeInSeconds); if (labInd > 1) { tStartTgt = (float) labTgt.items[labInd - 1].time; tStartSrc = (float) labSrc.items[labInd - 1].time; } else { tStartSrc = 0.0f; tStartTgt = 0.0f; } targetTime = MathUtils.linearMap(sourceTime, tStartSrc, labSrc.items[labInd].time, tStartTgt, labTgt.items[labInd].time); tgtF0Ind = SignalProcUtils.time2frameIndex(targetTime, f0Tgt.header.windowSizeInSeconds, f0Tgt.header.skipSizeInSeconds); } else // No labels given, just do a linear mapping between given source and target contours tgtF0Ind = MathUtils.linearMap(i, 0, f0Src.contour.length - 1, 0, f0Tgt.contour.length - 1); if (f0Src.contour[i] > 10.0f && f0Tgt.contour[tgtF0Ind] > 10.0f) pScales[i] = (float) (f0Tgt.contour[tgtF0Ind] / f0Src.contour[i]); else pScales[i] = 1.0f; pScalesTimes[i] = (float) sourceTime; } } else { setPScales(1.0f); setPScalesTimes(null); } } public void setTScales(float x) { tScales = new float[1]; tScales[0] = x; } public void setTScales(float[] x) { tScales = ArrayUtils.copy(x); } public void setTScalesTimes(float x) { tScalesTimes = new float[1]; tScalesTimes[0] = x; } public void setTScalesTimes(float[] x) { tScalesTimes = ArrayUtils.copy(x); } public void setPScales(float x) { pScales = new float[1]; pScales[0] = x; } public void setPScales(float[] x) { pScales = ArrayUtils.copy(x); } public void setPScalesTimes(float x) { pScalesTimes = new float[1]; pScalesTimes[0] = x; } public void setPScalesTimes(float[] x) { pScalesTimes = ArrayUtils.copy(x); } public boolean willProsodyBeModified() { int i; if (pScales != null) { for (i = 0; i < pScales.length; i++) { if (pScales[i] != 1.0f) return true; } } if (tScales != null) { for (i = 0; i < tScales.length; i++) { if (tScales[i] != 1.0f) return true; } } return false; } public void writeObject(String fileName) throws IOException { try { File file = new File(fileName); FileOutputStream fos = new FileOutputStream(fileName); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(this); oos.close(); } catch (IOException e) { throw e; } } public static BasicProsodyModifierParams readObject(String fileName) throws IOException, ClassNotFoundException { try { File file = new File(fileName); FileInputStream fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); BasicProsodyModifierParams bpmp = (BasicProsodyModifierParams) ois.readObject(); ois.close(); return bpmp; } catch (IOException e) { throw e; } catch (ClassNotFoundException e) { throw e; } } }