/** * Copyright 2000-2009 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.process; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import javax.sound.sampled.AudioFileFormat; 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.window.DynamicWindow; import marytts.signalproc.window.Window; import marytts.util.data.BufferedDoubleDataSource; import marytts.util.data.DoubleDataSource; import marytts.util.data.audio.AudioDoubleDataSource; import marytts.util.data.audio.DDSAudioInputStream; import marytts.util.io.LEDataInputStream; import marytts.util.io.LEDataOutputStream; import marytts.util.math.ComplexArray; import marytts.util.math.FFTMixedRadix; import marytts.util.math.MathUtils; import marytts.util.signal.SignalProcUtils; public class FDPSOLAProcessorOld extends VocalTractModifier { private DoubleDataSource input; private AudioInputStream inputAudio; private DDSAudioInputStream outputAudio; private VoiceModificationParametersPreprocessor modParams; private int numfrm; private int numfrmFixed; private int lpOrder; // LP analysis order private String outputFile; private String tempOutBinaryFile; private int origLen; private PitchMarks pm; private PsolaFrameProvider psFrm; private double wsFixed; private double ssFixed; private int numPeriods; private static int NUM_PITCH_SYNC_PERIODS = 3; private boolean bSilent; private LEDataOutputStream dout; private LEDataInputStream din; private DynamicWindow windowIn; private DynamicWindow windowOut; private double[] wgt; private double[] wgty; private int frmSize; private int newFrmSize; private int newPeriod; private int synthFrmInd; private double localDurDiff; private int repeatSkipCount; // -1:skip frame, 0:no repetition (use synthesized frame as it is), >0: number of repetitions for // synthesized frame private double localDurDiffSaved; private double sumLocalDurDiffs; private double nextAdd; private int synthSt; private int synthTotal; private int maxFrmSize; private int maxNewFrmSize; private int synthFrameInd; private boolean bLastFrame; private boolean bBroke; private int newFftSize; private int newMaxFreq; private int outBuffLen; private double[] outBuff; private int outBuffStart; private int totalWrittenToFile; private double[] ySynthBuff; private double[] wSynthBuff; private int ySynthInd; private double[] frm; private double[] frm2; private boolean bWarp; private double[] py; private double[] py2; private ComplexArray hy; private double[] frmy; private double frmEn; private double frmyEn; private double gain; private int newSkipSize; private int halfWin; private double[] newVScales; public FDPSOLAProcessorOld(String strInputFile, String strPitchFile, String strOutputFile, double[] pscales, double[] tscales, double[] escales, double[] vscales) throws UnsupportedAudioFileException, IOException { super(); inputAudio = AudioSystem.getAudioInputStream(new File(strInputFile)); input = new AudioDoubleDataSource(inputAudio); origLen = (int) input.getDataLength(); fs = (int) inputAudio.getFormat().getSampleRate(); lpOrder = SignalProcUtils.getLPOrder(fs); wsFixed = 0.02; ssFixed = 0.01; numPeriods = NUM_PITCH_SYNC_PERIODS; PitchReaderWriter f0 = new PitchReaderWriter(strPitchFile); pm = SignalProcUtils.pitchContour2pitchMarks(f0.contour, fs, origLen, f0.header.windowSizeInSeconds, f0.header.skipSizeInSeconds, true, 0); numfrm = pm.pitchMarks.length - numPeriods; // Total pitch synchronous frames (This is the actual number of frames to be // processed) numfrmFixed = (int) (Math.floor(((double) (origLen + pm.totalZerosToPadd) / fs - 0.5 * wsFixed) / ssFixed + 0.5) + 2); // Total // frames // if // the // analysis // was // fixed // skip-rate modParams = new VoiceModificationParametersPreprocessor(fs, lpOrder, pscales, tscales, escales, vscales, pm.pitchMarks, wsFixed, ssFixed, numfrm, numfrmFixed, numPeriods, false); outputFile = strOutputFile; initialise(); } public void initialise() throws FileNotFoundException { bSilent = false; // double [] tmpx = input.getAllData(); // double [] x = new double[origLen+pm.totalZerosToPadd]; // Arrays.fill(x, 0.0); // System.arraycopy(tmpx, 0, x, 0, origLen); psFrm = new PsolaFrameProvider(input, pm, modParams.fs, modParams.numPeriods); tempOutBinaryFile = outputFile + ".bin"; dout = new LEDataOutputStream(tempOutBinaryFile); windowIn = new DynamicWindow(Window.HANNING); windowOut = new DynamicWindow(Window.HANNING); frmSize = 0; newFrmSize = 0; newPeriod = 0; synthFrmInd = 0; localDurDiff = 0.0; repeatSkipCount = 0; // -1:skip frame, 0:no repetition (use synthesized frame as it is), >0: number of repetitions for // synthesized frame localDurDiffSaved = 0.0; sumLocalDurDiffs = 0.0; nextAdd = 0.0; synthSt = pm.pitchMarks[0]; synthTotal = 0; maxFrmSize = (int) (modParams.numPeriods * modParams.fs / 40.0); if ((maxFrmSize % 2) != 0) maxFrmSize++; maxNewFrmSize = (int) (Math.floor(maxFrmSize / MathUtils.min(modParams.pscalesVar) + 0.5)); if ((maxNewFrmSize % 2) != 0) maxNewFrmSize++; synthFrameInd = 0; bLastFrame = false; bBroke = false; fftSize = (int) Math.pow(2, (Math.ceil(Math.log((double) maxFrmSize) / Math.log(2.0)))); maxFreq = fftSize / 2 + 1; outBuffLen = 100; outBuff = MathUtils.zeros(outBuffLen); outBuffStart = 1; totalWrittenToFile = 0; ySynthBuff = MathUtils.zeros(maxNewFrmSize); wSynthBuff = MathUtils.zeros(maxNewFrmSize); ySynthInd = 1; } public void fdpsolaOnline() throws IOException { int kMax; int i, j, k, n, m; int tmpFix, tmpAdd, tmpMul; int wInd; double[] tmpvsc = new double[1]; int remain; int kInd; boolean isVoiced; for (i = 0; i < numfrm; i++) { frm2 = psFrm.getNextFrame(); if (bBroke) break; repeatSkipCount = 0; // -1:skip frame, 0:no repetition (use synthesized frame as it is), >0: number of repetitions for // synthesized frame // Compute new frame sizes, change in durations due to pitch scaling, and required compensation amount in samples // & // Find out which pitch-scaled frames to repeat/skip for overall duration // compensation frmSize = pm.pitchMarks[i + modParams.numPeriods] - pm.pitchMarks[i] + 1; if ((frmSize % 2) != 0) frmSize++; if (frmSize < 4) frmSize = 4; isVoiced = pm.f0s[i] > 10.0 ? true : false; if (isVoiced) { newFrmSize = (int) (Math.floor(frmSize / modParams.pscalesVar[i] + 0.5)); if ((newFrmSize % 2) != 0) newFrmSize++; if (newFrmSize < 4) newFrmSize = 4; } else newFrmSize = frmSize; newPeriod = (int) Math.floor(((double) newFrmSize) / modParams.numPeriods + 0.5); // Compute duration compensation required: // localDurDiffs(i) = (DESIRED)-(AFTER PITCHSCALING) // (-) if expansion occured, (+) if compression occured // We aim to make this as close to zero as possible in the following duration compensation step localDurDiff = nextAdd + (frmSize * modParams.tscalesVar[i] - newFrmSize) / modParams.numPeriods; nextAdd = 0; if (localDurDiff < -0.1 * newPeriod) // Expansion occured so skip this frame { repeatSkipCount--; if (i < numfrm - 1) { nextAdd = localDurDiff + newPeriod; localDurDiff = 0; } } else if (localDurDiff > 0.1 * newPeriod) // Compression occured so repeat this frame { while (localDurDiff > 0.1 * newPeriod) { repeatSkipCount++; localDurDiff -= newPeriod; } if (i < numfrm - 1) { nextAdd = localDurDiff; localDurDiff = 0; } } sumLocalDurDiffs += localDurDiff; if (i == numfrm - 1) { // Check the final length and perform additional repetitions if necessary localDurDiff = sumLocalDurDiffs; while (localDurDiff > 0) { repeatSkipCount++; localDurDiff -= newPeriod; } // } if (i == numfrm - 1) { repeatSkipCount++; bLastFrame = true; } if (repeatSkipCount > -1) { frm = MathUtils.zeros(frmSize); // System.arraycopy(x, pm.pitchMarks[i], frm, 0, Math.min(frmSize, origLen-pm.pitchMarks[i])); System.arraycopy(frm2, 0, frm, 0, frmSize); wgt = windowIn.values(frmSize); if (modParams.vscalesVar[i] != 1.0) bWarp = true; else bWarp = false; if ((isVoiced && modParams.pscalesVar[i] != 1.0) || bWarp) { newMaxFreq = (int) Math.floor(maxFreq / modParams.pscalesVar[i] + 0.5); if (newMaxFreq < 3) newMaxFreq = 3; if ((newMaxFreq % 2) != 1) newMaxFreq++; // This is for being able to use the FFT algorithm that works only with buffers of length power of two // If you have an FFT algorithm that works with any buffer size, simply remove this line // newMaxFreq = (int)Math.floor(0.5*MathUtils.closestPowerOfTwoAbove(2*(newMaxFreq-1))+1.5); // newFftSize = 2 * (newMaxFreq - 1); frmEn = SignalProcUtils.getEnergy(frm); // Compute LP and excitation spectrum initialise(modParams.lpOrder, modParams.fs, fftSize, true); // Perform only analysis windowIn.applyInline(frm, 0, frmSize); // Windowing applyInline(frm, 0, frmSize); // LP analysis // Expand/Compress the vocal tract spectrum in inverse manner py = MathUtils.interpolate(vtSpectrum, newMaxFreq); // Interpolated vocal tract spectrum // Perform vocal tract scaling if (bWarp) { tmpvsc[0] = modParams.vscalesVar[i]; newVScales = MathUtils.modifySize(tmpvsc, newMaxFreq); // Modify length to match current length of // spectrum for (k = 0; k < newVScales.length; k++) { if (newVScales[k] < 0.05) // Put a floor to avoid divide by zero newVScales[k] = 0.05; } py2 = new double[newMaxFreq]; for (k = 0; k < newMaxFreq; k++) { wInd = (int) Math.floor((k + 1) / newVScales[k] + 0.5); // Find new indices if (wInd < 1) wInd = 1; if (wInd > newMaxFreq) wInd = newMaxFreq; py2[k] = py[wInd - 1]; } System.arraycopy(py2, 0, py, 0, newMaxFreq); } // Create output DFT spectrum hy = new ComplexArray(newFftSize); hy.real = MathUtils.zeros(newFftSize); hy.imag = MathUtils.zeros(newFftSize); System.arraycopy(this.h.real, 0, hy.real, 0, Math.min(maxFreq, newFftSize)); System.arraycopy(this.h.imag, 0, hy.imag, 0, Math.min(maxFreq, newFftSize)); // Copy & paste samples if required (COMPLEX VERSION TO SUPPORT PSCALE<=0.5) // This version fills the spectrum by flipping and pasting the original freq bins as many times as required. kMax = 1; while (newMaxFreq > (kMax + 1) * (maxFreq - 2)) kMax++; for (k = 1; k <= kMax; k++) { tmpFix = (maxFreq - 2) * k; if (k % 2 == 1) // Odd mode { tmpAdd = maxFreq + 2; tmpMul = 1; } else { tmpAdd = -1; tmpMul = -1; } for (j = tmpFix + 3; j <= Math.min(newMaxFreq, maxFreq + tmpFix); j++) { hy.real[j - 1] = this.h.real[tmpMul * (tmpFix - j) + tmpAdd - 1]; hy.imag[j - 1] = this.h.imag[tmpMul * (tmpFix - j) + tmpAdd - 1]; } } hy.real[newMaxFreq - 1] = Math.sqrt(hy.real[newMaxFreq - 1] * hy.real[newMaxFreq - 1] + hy.imag[newMaxFreq - 1] * hy.imag[newMaxFreq - 1]); hy.imag[newMaxFreq - 1] = 0.0; // Convolution for (k = 1; k <= newMaxFreq; k++) { hy.real[k - 1] *= py[k - 1]; hy.imag[k - 1] *= py[k - 1]; } for (k = newMaxFreq + 1; k <= newFftSize; k++) { hy.real[k - 1] = hy.real[2 * newMaxFreq - 1 - k]; hy.imag[k - 1] = -hy.imag[2 * newMaxFreq - 1 - k]; } // Convert back to time domain // FFT.transform(hy.real, hy.imag, true); // hy = FFTArbitraryLength.ifft(hy); hy = FFTMixedRadix.ifft(hy); frmy = new double[newFrmSize]; System.arraycopy(hy.real, 0, frmy, 0, newFrmSize); frmyEn = SignalProcUtils.getEnergy(frmy); gain = (frmEn / Math.sqrt(frmSize)) / (frmyEn / Math.sqrt(newFrmSize)) * modParams.escalesVar[i]; } else { if (frmSize < newFrmSize) newFrmSize = frmSize; frmy = new double[newFrmSize]; for (k = 0; k < frmSize; k++) frmy[k] = frm[k] * wgt[k]; gain = modParams.escalesVar[i]; } // Energy scale compensation + modification for (k = 0; k < newFrmSize; k++) frmy[k] *= gain; for (j = 1; j <= repeatSkipCount + 1; j++) { if (isVoiced) newSkipSize = (int) Math.floor((pm.pitchMarks[i + 1] - pm.pitchMarks[i]) / modParams.pscalesVar[i] + 0.5); else newSkipSize = (int) Math.floor((pm.pitchMarks[i + 1] - pm.pitchMarks[i]) + 0.5); if ((i == numfrm - 1 && j == repeatSkipCount + 1)) // | (i~=numfrm & all(repeatSkipCounts(i+1:numfrm)==-1))) bLastFrame = true; else bLastFrame = false; synthFrameInd++; wgty = windowOut.values(newFrmSize); if (synthFrameInd == 1) // First frame: Do not window the first half of output speech frame to prevent // overflow in normalization with hanning coeffs { halfWin = (int) Math.floor(newFrmSize / 2.0 + 0.5); synthTotal = synthSt + newFrmSize; // Keep output in an overlap-add buffer if (ySynthInd + newFrmSize - 1 <= maxNewFrmSize) { for (k = ySynthInd; k <= ySynthInd + halfWin - 1; k++) { ySynthBuff[k - 1] = frmy[k - ySynthInd]; wSynthBuff[k - 1] = 1.0; } for (k = ySynthInd + halfWin; k <= ySynthInd + newFrmSize - 1; k++) { ySynthBuff[k - 1] += frmy[k - ySynthInd] * wgty[k - ySynthInd]; wSynthBuff[k - 1] += wgty[k - ySynthInd] * wgty[k - ySynthInd]; } } else { for (k = ySynthInd; k <= maxNewFrmSize; k++) { if (k - ySynthInd < halfWin) { ySynthBuff[k - 1] = frmy[k - ySynthInd]; wSynthBuff[k - 1] = 1.0; } else { ySynthBuff[k - 1] += frmy[k - ySynthInd] * wgty[k - ySynthInd]; wSynthBuff[k - 1] += wgty[k - ySynthInd] * wgty[k - ySynthInd]; } } for (k = 1; k <= newFrmSize - 1 - maxNewFrmSize + ySynthInd; k++) { if (maxNewFrmSize - ySynthInd + k < halfWin) { ySynthBuff[k - 1] = frmy[maxNewFrmSize - ySynthInd + k]; wSynthBuff[k - 1] = 1.0; } else { ySynthBuff[k - 1] += frmy[maxNewFrmSize - ySynthInd + k] * wgty[maxNewFrmSize - ySynthInd + k]; wSynthBuff[k - 1] += wgty[maxNewFrmSize - ySynthInd + k] * wgty[maxNewFrmSize - ySynthInd + k]; } } } // if (!bSilent) System.out.println("Synthesized using frame " + String.valueOf(i + 1) + " of " + String.valueOf(numfrm) + " " + String.valueOf(pm.pitchMarks[i]) + " " + String.valueOf(pm.pitchMarks[i + modParams.numPeriods])); } else if (bLastFrame) // Last frame: Do not window the second half of output speech frame to prevent overflow // in normalization with hanning coeffs { halfWin = (int) Math.floor(newFrmSize / 2.0 + 0.5); remain = newFrmSize - halfWin; synthTotal = synthSt + halfWin + remain - 1; // Keep output in an overlap-add buffer if (ySynthInd + newFrmSize - 1 <= maxNewFrmSize) { for (k = ySynthInd; k <= ySynthInd + halfWin - 1; k++) { ySynthBuff[k - 1] += frmy[k - ySynthInd] * wgty[k - ySynthInd]; wSynthBuff[k - 1] += wgty[k - ySynthInd] * wgty[k - ySynthInd]; } for (k = ySynthInd + halfWin; k <= ySynthInd + newFrmSize - 1; k++) { ySynthBuff[k - 1] += frmy[k - ySynthInd]; wSynthBuff[k - 1] = 1.0; } } else { for (k = ySynthInd; k <= maxNewFrmSize; k++) { if (k - ySynthInd < halfWin) { ySynthBuff[k - 1] += frmy[k - ySynthInd] * wgty[k - ySynthInd]; wSynthBuff[k - 1] += wgty[k - ySynthInd] * wgty[k - ySynthInd]; } else { ySynthBuff[k - 1] += frmy[k - ySynthInd]; wSynthBuff[k - 1] = 1.0; } } for (k = 1; k <= newFrmSize - 1 - maxNewFrmSize + ySynthInd; k++) { if (maxNewFrmSize - ySynthInd + k < halfWin) { ySynthBuff[k - 1] += frmy[maxNewFrmSize - ySynthInd + k] * wgty[maxNewFrmSize - ySynthInd + k]; wSynthBuff[k - 1] += wgty[maxNewFrmSize - ySynthInd + k] * wgty[maxNewFrmSize - ySynthInd + k]; } else { ySynthBuff[k - 1] += frmy[maxNewFrmSize - ySynthInd + k]; wSynthBuff[k - 1] = 1.0; } } } // if (!bSilent) System.out.println("Synthesized using frame " + String.valueOf(i + 1) + " of " + String.valueOf(numfrm) + " " + String.valueOf(pm.pitchMarks[i]) + " " + String.valueOf(pm.pitchMarks[i + modParams.numPeriods])); } else // Normal frame { if (!isVoiced && ((repeatSkipCount % 2) == 1)) // Reverse unvoiced repeated frames once in two consecutive // repetitions to reduce distortion frmy = SignalProcUtils.reverse(frmy); synthTotal = synthSt + newFrmSize; // Keep output in an overlap-add buffer if (ySynthInd + newFrmSize - 1 <= maxNewFrmSize) { for (k = ySynthInd; k <= ySynthInd + newFrmSize - 1; k++) { ySynthBuff[k - 1] += frmy[k - ySynthInd] * wgty[k - ySynthInd]; wSynthBuff[k - 1] += wgty[k - ySynthInd] * wgty[k - ySynthInd]; } } else { for (k = ySynthInd; k <= maxNewFrmSize; k++) { ySynthBuff[k - 1] += frmy[k - ySynthInd] * wgty[k - ySynthInd]; wSynthBuff[k - 1] += wgty[k - ySynthInd] * wgty[k - ySynthInd]; } for (k = 1; k <= newFrmSize - 1 - maxNewFrmSize + ySynthInd; k++) { ySynthBuff[k - 1] += frmy[k + maxNewFrmSize - ySynthInd] * wgty[k + maxNewFrmSize - ySynthInd]; wSynthBuff[k - 1] += wgty[k + maxNewFrmSize - ySynthInd] * wgty[k + maxNewFrmSize - ySynthInd]; } } // if (!bSilent) { if (j == 1) System.out.println("Synthesized using frame " + String.valueOf(i + 1) + " of " + String.valueOf(numfrm) + " " + String.valueOf(pm.pitchMarks[i]) + " " + String.valueOf(pm.pitchMarks[i + modParams.numPeriods])); else System.out.println("Repeated using frame " + String.valueOf(i + 1) + " of " + String.valueOf(numfrm) + " " + String.valueOf(pm.pitchMarks[i]) + " " + String.valueOf(pm.pitchMarks[i + modParams.numPeriods])); } } // Write to output buffer for (k = 0; k <= newSkipSize - 1; k++) { kInd = (k + ySynthInd) % maxNewFrmSize; if (kInd == 0) kInd = maxNewFrmSize; if (wSynthBuff[kInd - 1] > 0.0) outBuff[outBuffStart - 1] = ySynthBuff[kInd - 1] / wSynthBuff[kInd - 1]; else outBuff[outBuffStart - 1] = ySynthBuff[kInd - 1]; ySynthBuff[kInd - 1] = 0.0; wSynthBuff[kInd - 1] = 0.0; outBuffStart++; if (outBuffStart > outBuffLen) { if (modParams.tscaleSingle != 1.0 || totalWrittenToFile + outBuffLen <= origLen) { dout.writeDouble(outBuff, 0, outBuffLen); totalWrittenToFile += outBuffLen; } else { dout.writeDouble(outBuff, 0, origLen - totalWrittenToFile); totalWrittenToFile = origLen; } outBuffStart = 1; } } // synthSt += newSkipSize; // if (!bLastFrame) // { if (ySynthInd + newSkipSize <= maxNewFrmSize) ySynthInd += newSkipSize; else ySynthInd += newSkipSize - maxNewFrmSize; // } // /////// if (bLastFrame) { bBroke = true; break; } } } else { if (!bSilent) System.out.println("Skipped frame " + String.valueOf(i + 1) + " of " + String.valueOf(numfrm)); } } if (modParams.tscaleSingle == 1.0) synthTotal = origLen; if (outBuffLen > synthTotal) outBuffLen = synthTotal; // Write the final segment for (k = synthSt; k <= synthTotal; k++) { kInd = (k - synthSt + ySynthInd) % maxNewFrmSize; if (kInd == 0) kInd = maxNewFrmSize; if (wSynthBuff[kInd - 1] > 0.0) outBuff[outBuffStart - 1] = ySynthBuff[kInd - 1] / wSynthBuff[kInd - 1]; else outBuff[outBuffStart - 1] = ySynthBuff[kInd - 1]; ySynthBuff[kInd - 1] = 0.0; wSynthBuff[kInd - 1] = 0.0; outBuffStart++; if (outBuffStart > outBuffLen) { if (modParams.tscaleSingle != 1.0 || totalWrittenToFile + outBuffLen <= origLen) { dout.writeDouble(outBuff, 0, outBuffLen); totalWrittenToFile += outBuffLen; } else { dout.writeDouble(outBuff, 0, origLen - totalWrittenToFile); totalWrittenToFile = origLen; } outBuffStart = 1; } } if (outBuffStart > 1) { if (modParams.tscaleSingle != 1.0 || totalWrittenToFile + outBuffStart - 1 <= origLen) { dout.writeDouble(outBuff, 0, outBuffStart - 1); totalWrittenToFile += outBuffStart - 1; } else { dout.writeDouble(outBuff, 0, origLen - totalWrittenToFile); totalWrittenToFile = origLen; } } // dout.close(); // Read the temp binary file into a wav file and delete the temp binary file din = new LEDataInputStream(tempOutBinaryFile); double[] yOut = din.readDouble(totalWrittenToFile); din.close(); double tmpMax = MathUtils.getAbsMax(yOut); if (tmpMax > 32735) { for (i = 0; i < yOut.length; i++) yOut[i] *= 32735 / tmpMax; } outputAudio = new DDSAudioInputStream(new BufferedDoubleDataSource(yOut), inputAudio.getFormat()); AudioSystem.write(outputAudio, AudioFileFormat.Type.WAVE, new File(outputFile)); File tmpFile = new File(tempOutBinaryFile); tmpFile.delete(); // } public static void main(String[] args) throws Exception { String strOutputFile = args[0].substring(0, args[0].length() - 4) + "_fdJavOld.wav"; String strPitchFile = args[0].substring(0, args[0].length() - 4) + ".ptc"; double[] pscales = { 1.2, 0.3 }; double[] tscales = { 1.5 }; double[] escales = { 1.0 }; double[] vscales = { 1.8, 0.4 }; FDPSOLAProcessorOld fd = new FDPSOLAProcessorOld(args[0], strPitchFile, strOutputFile, pscales, tscales, escales, vscales); fd.fdpsolaOnline(); } }