/**
* Copyright 2007 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.sinusoidal.pitch;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import marytts.signalproc.analysis.PitchMarks;
import marytts.signalproc.analysis.PitchReaderWriter;
import marytts.signalproc.sinusoidal.NonharmonicSinusoidalSpeechFrame;
import marytts.signalproc.sinusoidal.NonharmonicSinusoidalSpeechSignal;
import marytts.signalproc.sinusoidal.PitchSynchronousSinusoidalAnalyzer;
import marytts.signalproc.sinusoidal.SinusoidalAnalysisParams;
import marytts.signalproc.window.Window;
import marytts.util.data.audio.AudioDoubleDataSource;
import marytts.util.math.MathUtils;
import marytts.util.signal.SignalProcUtils;
/**
* This class implements the comb-filter based pitch tracker in:
*
* Quatieri, T. F. Discrete-Time Speech Signal Processing: Principles and Practice. Prentice-Hall Inc. 2001. (Chapter 9 –
* Sinusoidal Analysis/Synthesis)
*
* @author Oytun Türk
*/
public class CombFilterPitchTracker extends BaseSinusoidalPitchTracker {
public CombFilterPitchTracker() {
}
public double performanceCriterion(NonharmonicSinusoidalSpeechFrame sinFrame, float f0Candidate, int samplingRate) {
double Q = 0.0;
int endIndex = 0;
float f0CandidateInRadians = SignalProcUtils.hz2radian(f0Candidate, samplingRate);
while (sinFrame.sinusoids[endIndex].freq < f0CandidateInRadians) {
if (endIndex >= sinFrame.sinusoids.length - 1)
break;
endIndex++;
}
for (int k = 0; k <= endIndex; k++)
Q += sinFrame.sinusoids[k].amp
* sinFrame.sinusoids[k].amp
* Math.cos(MathUtils.TWOPI * SignalProcUtils.radian2hz(sinFrame.sinusoids[k].freq, samplingRate)
/ f0Candidate);
return Q;
}
public static void main(String[] args) throws UnsupportedAudioFileException, IOException {
AudioInputStream inputAudio = AudioSystem.getAudioInputStream(new File(args[0]));
int samplingRate = (int) inputAudio.getFormat().getSampleRate();
AudioDoubleDataSource signal = new AudioDoubleDataSource(inputAudio);
double[] x = signal.getAllData();
float searchStepInHz = 0.5f;
float minFreqInHz = 40.0f;
float maxFreqInHz = 400.0f;
float windowSizeInSeconds = SinusoidalAnalysisParams.DEFAULT_ANALYSIS_WINDOW_SIZE;
float skipSizeInSeconds = SinusoidalAnalysisParams.DEFAULT_ANALYSIS_SKIP_SIZE;
float deltaInHz = SinusoidalAnalysisParams.DEFAULT_DELTA_IN_HZ;
int windowType = Window.HAMMING;
double startFreqInHz = 0.0;
double endFreqInHz = 0.5 * samplingRate;
boolean bRefinePeakEstimatesParabola = true;
boolean bRefinePeakEstimatesBias = true;
boolean bSpectralReassignment = true;
boolean bAdjustNeighFreqDependent = true;
SinusoidalAnalysisParams params = new SinusoidalAnalysisParams(samplingRate, startFreqInHz, endFreqInHz, windowType,
bRefinePeakEstimatesParabola, bRefinePeakEstimatesBias, bSpectralReassignment, bAdjustNeighFreqDependent);
String strPitchFileIn = args[0].substring(0, args[0].length() - 4) + ".ptc";
PitchReaderWriter f0 = new PitchReaderWriter(strPitchFileIn);
int pitchMarkOffset = 0;
PitchMarks pm = SignalProcUtils.pitchContour2pitchMarks(f0.contour, samplingRate, x.length,
f0.header.windowSizeInSeconds, f0.header.skipSizeInSeconds, true, pitchMarkOffset);
PitchSynchronousSinusoidalAnalyzer sa = new PitchSynchronousSinusoidalAnalyzer(params);
// sa.setSinAnaFFTSize(4096);
NonharmonicSinusoidalSpeechSignal ss = sa.extractSinusoidsFixedRate(x, windowSizeInSeconds, skipSizeInSeconds, deltaInHz);
CombFilterPitchTracker p = new CombFilterPitchTracker();
float[] f0s = p.pitchTrack(ss, samplingRate, searchStepInHz, minFreqInHz, maxFreqInHz);
String strPitchFileOut = args[0].substring(0, args[0].length() - 4) + ".ptcSin";
PitchReaderWriter.write_pitch_file(strPitchFileOut, f0s, windowSizeInSeconds, skipSizeInSeconds, samplingRate);
for (int i = 0; i < f0s.length; i++)
System.out.println(String.valueOf(i * skipSizeInSeconds + 0.5f * windowSizeInSeconds) + " sec. = "
+ String.valueOf(f0s[i]));
}
}