// st: Sinusoidal tracks // absMaxDesired: Desired absolute maximum of the output public double[] synthesize(SinusoidalTracks st, boolean isSilentSynthesis) { int n; // discrete time index int i, j; int nStart, nEnd, pStart, pEnd; float t; // continuous time float t2; // continuous time squared float t3; // continuous time cubed float tFinal = st.getOriginalDuration(); int nFinal = (int) (Math.floor(tFinal * st.fs + 0.5)); double[] y = new double[nFinal + 1]; Arrays.fill(y, 0.0); float currentAmp; float currentTheta; double alpha, beta; int M; float T; // Number of samples between consecutive frames (equals to pitch period in pitch // synchronous analysis/synthesis) float T2; // T squared float T3; // T cubed double oneOverTwoPi = 1.0 / MathUtils.TWOPI; double term1, term2; float currentTime; // For debugging purposes for (i = 0; i < st.totalTracks; i++) { for (j = 0; j < st.tracks[i].totalSins - 1; j++) { if (st.tracks[i].states[j] != SinusoidalTrack.TURNED_OFF) { pStart = (int) Math.floor(st.tracks[i].times[j] * st.fs + 0.5); pEnd = (int) Math.floor(st.tracks[i].times[j + 1] * st.fs + 0.5); nStart = Math.max(0, pStart); nEnd = Math.max(0, pEnd); nStart = Math.min(y.length - 1, nStart); nEnd = Math.min(y.length - 1, nEnd); // currentTime = 0.5f*(nEnd+nStart)/st.fs; // System.out.println("currentTime=" + String.valueOf(currentTime)); for (n = nStart; n < nEnd; n++) { if (false) // Direct synthesis { currentAmp = st.tracks[i].amps[j]; currentTheta = (n - nStart) * st.tracks[i].freqs[j] + st.tracks[i].phases[j]; y[n] += currentAmp * Math.cos(currentTheta); } else // Synthesis with interpolation { // Amplitude interpolation currentAmp = st.tracks[i].amps[j] + (st.tracks[i].amps[j + 1] - st.tracks[i].amps[j]) * ((float) n - pStart) / (pEnd - pStart + 1); T = (pEnd - pStart); if (n == nStart && st.tracks[i].states[j] == SinusoidalTrack.TURNED_ON) // Turning on a track { // Quatieri currentTheta = st.tracks[i].phases[j + 1] - T * st.tracks[i].freqs[j + 1]; currentAmp = 0.0f; } else if (n == nStart && st.tracks[i].states[j] == SinusoidalTrack.TURNED_OFF && j > 0) // Turning off a track { // Quatieri currentTheta = st.tracks[i].phases[j - 1] + T * st.tracks[i].freqs[j - 1]; currentAmp = 0.0f; } else // Cubic phase interpolation { // Quatieri M = (int) (Math.floor( oneOverTwoPi * ((st.tracks[i].phases[j] + T * st.tracks[i].freqs[j] - st.tracks[i].phases[j + 1]) + (st.tracks[i].freqs[j + 1] - st.tracks[i].freqs[j]) * 0.5 * T) + 0.5)); term1 = st.tracks[i].phases[j + 1] - st.tracks[i].phases[j] - T * st.tracks[i].freqs[j] + M * MathUtils.TWOPI; term2 = st.tracks[i].freqs[j + 1] - st.tracks[i].freqs[j]; T2 = T * T; T3 = T * T2; alpha = 3.0 * term1 / T2 - term2 / T; beta = -2 * term1 / T3 + term2 / T2; t = ((float) n - nStart); t2 = t * t; t3 = t * t2; // Quatieri currentTheta = (float) (st.tracks[i].phases[j] + st.tracks[i].freqs[j] * t + alpha * t2 + beta * t3); } // Synthesis y[n] += currentAmp * Math.cos(currentTheta); } // System.out.println(String.valueOf(currentTheta)); } } } if (!isSilentSynthesis) System.out.println( "Synthesized track " + String.valueOf(i + 1) + " of " + String.valueOf(st.totalTracks)); } y = MathUtils.multiply(y, st.absMaxOriginal / MathUtils.getAbsMax(y)); return y; }
public static void main(String[] args) throws UnsupportedAudioFileException, IOException { // File input AudioInputStream inputAudio = AudioSystem.getAudioInputStream(new File(args[0])); int samplingRate = (int) inputAudio.getFormat().getSampleRate(); AudioDoubleDataSource signal = new AudioDoubleDataSource(inputAudio); double[] x = signal.getAllData(); double maxOrig = MathUtils.getAbsMax(x); SinusoidalAnalyzer sa = null; SinusoidalTracks st = null; PitchSynchronousSinusoidalAnalyzer pa = null; // // Analysis float deltaInHz = SinusoidalAnalysisParams.DEFAULT_DELTA_IN_HZ; float numPeriods = PitchSynchronousSinusoidalAnalyzer.DEFAULT_ANALYSIS_PERIODS; boolean isSilentSynthesis = false; int windowType = Window.HANNING; boolean bRefinePeakEstimatesParabola = false; boolean bRefinePeakEstimatesBias = false; boolean bSpectralReassignment = false; boolean bAdjustNeighFreqDependent = false; // int spectralEnvelopeType = SinusoidalAnalysisParams.LP_SPEC; int spectralEnvelopeType = SinusoidalAnalysisParams.SEEVOC_SPEC; float[] initialPeakLocationsInHz = null; initialPeakLocationsInHz = new float[1]; for (int i = 0; i < 1; i++) initialPeakLocationsInHz[i] = (i + 1) * 350.0f; boolean isFixedRateAnalysis = false; boolean isRealSpeech = true; double startFreqInHz = 0.0; double endFreqInHz = 0.5 * samplingRate; SinusoidalAnalysisParams params = new SinusoidalAnalysisParams( samplingRate, startFreqInHz, endFreqInHz, windowType, bRefinePeakEstimatesParabola, bRefinePeakEstimatesBias, bSpectralReassignment, bAdjustNeighFreqDependent); if (isFixedRateAnalysis) { // Fixed window size and skip rate analysis double[] f0s = null; float ws_f0 = -1.0f; float ss_f0 = -1.0f; sa = new SinusoidalAnalyzer(params); if (spectralEnvelopeType == SinusoidalAnalysisParams.SEEVOC_SPEC) // Pitch info needed { String strPitchFile = args[0].substring(0, args[0].length() - 4) + ".ptc"; PitchReaderWriter f0 = new PitchReaderWriter(strPitchFile); f0s = f0.contour; ws_f0 = (float) f0.header.windowSizeInSeconds; ss_f0 = (float) f0.header.skipSizeInSeconds; } st = sa.analyzeFixedRate( x, 0.020f, 0.010f, deltaInHz, spectralEnvelopeType, f0s, ws_f0, ss_f0); // } else { // Pitch synchronous analysis String strPitchFile = args[0].substring(0, args[0].length() - 4) + ".ptc"; PitchReaderWriter f0 = new PitchReaderWriter(strPitchFile); int pitchMarkOffset = 0; PitchMarks pm = SignalProcUtils.pitchContour2pitchMarks( f0.contour, samplingRate, x.length, f0.header.windowSizeInSeconds, f0.header.skipSizeInSeconds, true, pitchMarkOffset); pa = new PitchSynchronousSinusoidalAnalyzer(params); st = pa.analyzePitchSynchronous( x, pm, numPeriods, -1.0f, deltaInHz, spectralEnvelopeType, initialPeakLocationsInHz); isSilentSynthesis = false; } // // Resynthesis PeakMatchedSinusoidalSynthesizer ss = new PeakMatchedSinusoidalSynthesizer(samplingRate); x = ss.synthesize(st, isSilentSynthesis); // // File output DDSAudioInputStream outputAudio = new DDSAudioInputStream(new BufferedDoubleDataSource(x), inputAudio.getFormat()); String outFileName = args[0].substring(0, args[0].length() - 4) + "_sinResynthFullbandPitchSynch.wav"; AudioSystem.write(outputAudio, AudioFileFormat.Type.WAVE, new File(outFileName)); // }