/** * Copyright 2004-2006 DFKI GmbH. * All Rights Reserved. Use is subject to license terms. * * This file is part of MARY TTS. * * MARY TTS is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package marytts.signalproc.analysis; import marytts.util.data.ESTTrackReader; import marytts.util.math.ArrayUtils; import marytts.util.math.MathUtils; import marytts.util.signal.SignalProcUtils; /** * * A wrapper class to store pitch marks as integer sample indices * * @author Oytun Türk */ public class PitchMarks { public int[] pitchMarks; // N+1 pitch marks if we have N periods public float[] f0s; // N f0 values, 0th corresponds to f0 of waveform between [pitchMarks[0],pitchMarks[1]) public int totalZerosToPadd; public PitchMarks() { pitchMarks = null; f0s = null; totalZerosToPadd = 0; } // Initialize pitch marks from an ESTTrackReader // This does not handle unvoiced parts // So, f0s should be set to 0 in the unvoiced regions outside this code if required // One can use findAndSetUnvoicedF0s function to do this using the output of the autocorrelation based pitch tracker public PitchMarks(ESTTrackReader pmFile, int samplingRateInHz) { this(); int frameEnd = 0; int frameStart = 0; if (pmFile != null && pmFile.getNumFrames() > 0) { frameEnd = (int) ((double) pmFile.getTime(0) * (double) (samplingRateInHz)); if (frameEnd > 0) { pitchMarks = new int[pmFile.getNumFrames() + 1]; f0s = new float[pmFile.getNumFrames()]; pitchMarks[0] = 0; for (int f = 0; f < pmFile.getNumFrames(); f++) { frameEnd = (int) ((double) pmFile.getTime(f) * (double) (samplingRateInHz)); pitchMarks[f + 1] = frameEnd; if (f > 0) f0s[f] = 1.0f / (pmFile.getTime(f) - pmFile.getTime(f - 1)); else f0s[f] = 1.0f / pmFile.getTime(f); } } else { pitchMarks = new int[pmFile.getNumFrames()]; f0s = new float[pmFile.getNumFrames() - 1]; pitchMarks[0] = 0; for (int f = 1; f < pmFile.getNumFrames(); f++) { frameEnd = (int) ((double) pmFile.getTime(f) * (double) (samplingRateInHz)); pitchMarks[f] = frameEnd; if (f > 0) f0s[f - 1] = 1.0f / (pmFile.getTime(f) - pmFile.getTime(f - 1)); else f0s[f - 1] = 1.0f / pmFile.getTime(f); } } } } // count=total pitch marks public PitchMarks(int count, int[] pitchMarksIn, float[] f0sIn, int totalZerosToPaddIn) { if (count > 1) { pitchMarks = new int[count]; f0s = new float[count - 1]; System.arraycopy(pitchMarksIn, 0, pitchMarks, 0, Math.min(pitchMarksIn.length, count)); System.arraycopy(f0sIn, 0, f0s, 0, Math.min(f0sIn.length, count - 1)); } else { pitchMarks = null; f0s = null; } totalZerosToPadd = Math.max(0, totalZerosToPaddIn); } public void findAndSetUnvoicedF0s(float[] f0sRef, PitchFileHeader f0Header, int samplingRateInHz) { double[] f0sRefDouble = ArrayUtils.copyFloat2Double(f0sRef); findAndSetUnvoicedF0s(f0sRefDouble, f0Header, samplingRateInHz); } public void findAndSetUnvoicedF0s(double[] f0sRef, PitchFileHeader f0Header, int samplingRateInHz) { // MaryUtils.plot(f0s); // MaryUtils.plot(f0sRef); int i; if (pitchMarks != null && pitchMarks.length > 1) { float[] times = new float[f0sRef.length]; for (i = 0; i < f0sRef.length; i++) times[i] = (float) SignalProcUtils.frameIndex2Time(i, f0Header.windowSizeInSeconds, f0Header.skipSizeInSeconds); int currentRefIndex; float currentTime; for (i = 0; i < f0s.length; i++) { currentTime = SignalProcUtils.sample2time(pitchMarks[i + 1], samplingRateInHz); currentRefIndex = MathUtils.findClosest(times, currentTime); if (f0sRef[currentRefIndex] < 10.0) f0s[i] = (float) f0sRef[currentRefIndex]; } } // MaryUtils.plot(f0s); } }