//----------------------------------------------------------------------------- // SetParametersForGetWindowedWaveform() //----------------------------------------------------------------------------- void SetParametersForGetWindowedWaveform(int halfWindowLength, int xLength, double currentPosition, int fs, double currentF0, int[] baseIndex, int[] safeIndex, double[] window) { for (var i = -halfWindowLength; i <= halfWindowLength; i++) { baseIndex[i + halfWindowLength] = i; } var origin = MatlabFunctions.MatlabRound(currentPosition * fs + 0.001); for (int i = 0, limit = halfWindowLength * 2; i <= limit; i++) { safeIndex[i] = Math.Min(xLength - 1, Math.Max(0, origin + baseIndex[i])); } var average = 0.0; for (int i = 0, limit = halfWindowLength * 2; i <= limit; i++) { var position = baseIndex[i] / 1.5 / fs; window[i] = 0.5 * Math.Cos(Math.PI * position * currentF0) + 0.5; average += window[i] * window[i]; } average = Math.Sqrt(average); for (int i = 0, limit = halfWindowLength * 2; i <= limit; i++) { window[i] /= average; } }
//----------------------------------------------------------------------------- // GetCoarseAperiodicity() calculates the aperiodicity in multiples of 3 kHz. // The upper limit is given based on the sampling frequency. //----------------------------------------------------------------------------- private void GetCoarseAperiodicity(double[] staticGroupDelay, int fs, int fftSize, int numberOfAperiodicities, double[] window, ForwardRealFFT forwardRealFFT, SubSequence <double> coarseAperiodicity) { var boundary = MatlabFunctions.MatlabRound(fftSize * 8.0 / window.Length); var halfWindowLength = window.Length / 2; Array.Clear(forwardRealFFT.Waveform, 0, fftSize); var powerSpectrum = new double[fftSize / 2 + 1]; for (var i = 0; i < numberOfAperiodicities; i++) { var center = (int)(FrequencyInterval * (i + 1) * fftSize / fs); for (int j = 0, limit = halfWindowLength * 2; j <= limit; j++) { forwardRealFFT.Waveform[j] = staticGroupDelay[center - halfWindowLength + j] * window[j]; } FFT.Execute(forwardRealFFT.ForwardFFT); var spectrum = forwardRealFFT.Spectrum; for (int j = 0, limit = fftSize / 2; j <= limit; j++) { powerSpectrum[j] = spectrum[j].Real * spectrum[j].Real + spectrum[j].Imaginary * spectrum[j].Imaginary; } Array.Sort(powerSpectrum); for (int j = 1, limit = fftSize / 2; j <= limit; j++) { powerSpectrum[j] += powerSpectrum[j - 1]; } coarseAperiodicity[i] = 10.0 * Math.Log10(powerSpectrum[fftSize / 2 - boundary - 1] / powerSpectrum[fftSize / 2]); } }
//----------------------------------------------------------------------------- // GetWindowedWaveform() windows the waveform by F0-adaptive window //----------------------------------------------------------------------------- void GetWindowedWaveform(double[] x, int fs, double currentF0, double currentPosition, ForwardRealFFT forwardRealFFT) { var halfWindowLength = MatlabFunctions.MatlabRound(1.5 * fs / currentF0); var baseIndex = new int[halfWindowLength * 2 + 1]; var safeIndex = new int[halfWindowLength * 2 + 1]; var window = new double[halfWindowLength * 2 + 1]; SetParametersForGetWindowedWaveform(halfWindowLength, x.Length, currentPosition, fs, currentF0, baseIndex, safeIndex, window); // F0-adaptive windowing var waveForm = forwardRealFFT.Waveform; for (int i = 0, limit = halfWindowLength * 2; i <= limit; i++) { waveForm[i] = x[safeIndex[i]] * window[i] + Rand.Next() * SafeGuardMinimum; } var tmpWeight1 = waveForm.Take(halfWindowLength * 2 + 1).Sum(); var tmpWeight2 = window.Sum(); var weightingCoefficient = tmpWeight1 / tmpWeight2; for (int i = 0, limit = halfWindowLength * 2; i <= limit; i++) { waveForm[i] -= window[i] * weightingCoefficient; } }
public static void LinearSmoothing(double[] input, double width, int fs, int fftSize, double[] output) { var boundary = (int)(width * fftSize / fs) + 1; // These parameters are set by the other function. var mirroringSpectrum = new double[fftSize / 2 + boundary * 2 + 1]; var mirroringSegment = new double[fftSize / 2 + boundary * 2 + 1]; var frequencyAxis = new double[fftSize / 2 + 1]; SetParametersForLinearSmoothing(boundary, fftSize, fs, width, input, mirroringSpectrum, mirroringSegment, frequencyAxis); var lowLevels = new double[fftSize / 2 + 1]; var highLevels = new double[fftSize / 2 + 1]; var originOfMirroringAxis = -(boundary - 0.5) * fs / fftSize; var discreteFrequencyInterval = (double)fs / fftSize; MatlabFunctions.Interp1Q(originOfMirroringAxis, discreteFrequencyInterval, mirroringSegment.SubSequence(0, fftSize / 2 + boundary * 2 + 1), frequencyAxis.SubSequence(0, fftSize / 2 + 1), lowLevels); for (int i = 0, limit = fftSize / 2; i <= limit; i++) { frequencyAxis[i] += width; } MatlabFunctions.Interp1Q(originOfMirroringAxis, discreteFrequencyInterval, mirroringSegment.SubSequence(0, fftSize / 2 + boundary * 2 + 1), frequencyAxis.SubSequence(0, fftSize / 2 + 1), highLevels); for (int i = 0, limit = fftSize / 2; i <= limit; i++) { output[i] = (highLevels[i] - lowLevels[i]) / width; } }
void GetTimeBase(double[] f0, int f0Length, int startSample, int numberOfSamples) { var coarseTimeAxis = new double[f0Length + Handoff]; var coarseF0 = new double[f0Length + Handoff]; var coarseVUV = new double[f0Length + Handoff]; GetTemporalParametersForTimeBase(f0, f0Length, coarseTimeAxis, coarseF0, coarseVUV); var interpolatedF0 = new double[numberOfSamples]; var timeAxis = Enumerable.Range(0, numberOfSamples).Select((i) => (i + startSample) / (double)SampleRate).ToArray(); var pointer = Buffer.HeadIndex; MatlabFunctions.Interp1(coarseTimeAxis, coarseF0, timeAxis, interpolatedF0); MatlabFunctions.Interp1(coarseTimeAxis, coarseVUV, timeAxis, Buffer.InterpolatedVUV[pointer]); var interpolatedVUV = Buffer.InterpolatedVUV[pointer]; for (var i = 0; i < numberOfSamples; i++) { interpolatedVUV[i] = interpolatedVUV[i] > 0.5 ? 1.0 : 0.0; interpolatedF0[i] = interpolatedVUV[i] == 0.0 ? DefaultF0 : interpolatedF0[i]; } GetPulseLocationsForTimeBase(interpolatedF0, timeAxis, numberOfSamples, coarseTimeAxis[0]); HandoffF0 = interpolatedF0[numberOfSamples - 1]; }
//----------------------------------------------------------------------------- // GetAperiodicResponse() calculates an aperiodic response. //----------------------------------------------------------------------------- void GetAperiodicResponse(int noiseSize, int fftSize, double[] spectrum, double[] aperiodicRatio, double currentVUV, ForwardRealFFT forwardRealFFT, InverseRealFFT inverseRealFFT, MinimumPhaseAnalysis minimumPhase, double[] aperiodicResponse) { GetNoiseSpectrum(noiseSize, fftSize, forwardRealFFT); var logSpectrum = minimumPhase.LogSpectrum; if (currentVUV != 0.0) { for (int i = 0, limit = minimumPhase.FFTSize / 2; i <= limit; i++) { logSpectrum[i] = Math.Log(spectrum[i] * aperiodicRatio[i]) / 2.0; } } else { for (int i = 0, limit = minimumPhase.FFTSize / 2; i <= limit; i++) { logSpectrum[i] = Math.Log(spectrum[i]) / 2.0; } } Common.GetMinimumPhaseSpectrum(minimumPhase); var minimumPhaseSpectrum = minimumPhase.MinimumPhaseSpectrum; Array.Copy(minimumPhaseSpectrum, 0, inverseRealFFT.Spectrum, 0, fftSize / 2 + 1); for (int i = 0, limit = fftSize / 2; i <= limit; i++) { var real = minimumPhaseSpectrum[i].Real * forwardRealFFT.Spectrum[i].Real - minimumPhaseSpectrum[i].Imaginary * forwardRealFFT.Spectrum[i].Imaginary; var imaginary = minimumPhaseSpectrum[i].Real * forwardRealFFT.Spectrum[i].Imaginary + minimumPhaseSpectrum[i].Imaginary * forwardRealFFT.Spectrum[i].Real; inverseRealFFT.Spectrum[i] = new Complex(real, imaginary); } FFT.Execute(inverseRealFFT.InverseFFT); MatlabFunctions.FFTShift(inverseRealFFT.Waveform.SubSequence(0, fftSize), aperiodicResponse); }
void GetPulseLocationsForTimeBase(double[] interpolatedF0, double[] timeAxis, int numberOfSamples, double origin) { var totalPhase = new double[numberOfSamples + Handoff]; totalPhase[0] = Handoff == 1 ? HandoffPhase : PI2 * interpolatedF0[0] / SampleRate; totalPhase[1] = totalPhase[0] + PI2 * interpolatedF0[0] / SampleRate; for (int i = 1 + Handoff, limit = numberOfSamples + Handoff; i < limit; i++) { totalPhase[i] = totalPhase[i - 1] + PI2 * interpolatedF0[i - Handoff] / SampleRate; } HandoffPhase = totalPhase[numberOfSamples - 1 + Handoff]; var wrapPhase = totalPhase.Select((t) => t % PI2).ToArray(); var wrapPhaseABS = wrapPhase.Zip(wrapPhase.Skip(1), (w, nw) => Math.Abs(nw - w)).Append(0.0).ToArray(); var pointer = Buffer.HeadIndex; var numberOfPulses = 0; for (int i = 0, limit = numberOfSamples - 1 + Handoff; i < limit; i++) { if (wrapPhaseABS[i] > Math.PI) { Buffer.PulseLocations[pointer][numberOfPulses] = timeAxis[i] - (double)Handoff / SampleRate; Buffer.PulseLocationIndex[pointer][numberOfPulses] = MatlabFunctions.MatlabRound(Buffer.PulseLocations[pointer][numberOfPulses] * SampleRate); numberOfPulses++; } } Buffer.NumberOfPulses[pointer] = numberOfPulses; if (numberOfPulses != 0) { LastLocation = Buffer.PulseLocationIndex[pointer][numberOfPulses - 1]; } }
//----------------------------------------------------------------------------- // GetPeriodicResponse() calculates an aperiodic response. //----------------------------------------------------------------------------- void GetPeriodicResponse(int fftSize, double[] spectrum, double[] aperiodicRatio, double currentVUV, InverseRealFFT inverseRealFFT, MinimumPhaseAnalysis minimumPhase, double[] dcRemover, double fractionalTimeShift, int fs, double[] periodicResponse) { if (currentVUV <= 0.5 || aperiodicRatio[0] > 0.999) { Array.Clear(periodicResponse, 0, fftSize); return; } var logSpectrum = minimumPhase.LogSpectrum; for (int i = 0, limit = minimumPhase.FFTSize / 2; i <= limit; i++) { logSpectrum[i] = Math.Log(spectrum[i] * (1.0 - aperiodicRatio[i]) + SafeGuardMinimum) / 2.0; } Common.GetMinimumPhaseSpectrum(minimumPhase); Array.Copy(minimumPhase.MinimumPhaseSpectrum, 0, inverseRealFFT.Spectrum, 0, fftSize / 2 + 1); double coefficient = PI2 * fractionalTimeShift * fs / fftSize; GetSpectrumWithFractionalTimeShift(fftSize, coefficient, inverseRealFFT); FFT.Execute(inverseRealFFT.InverseFFT); MatlabFunctions.FFTShift(inverseRealFFT.Waveform.SubSequence(0, fftSize), periodicResponse); RemoveDCComponent(periodicResponse, fftSize, dcRemover, periodicResponse); }
void GetCentroid(double[] x, int fs, double currentF0, int fftSize, double currentPosition, ForwardRealFFT forwardRealFFT, double[] centroid) { Array.Clear(forwardRealFFT.Waveform, 0, fftSize); GetWindowedWaveform(x, fs, currentF0, currentPosition, WindowType.Blackman, 4.0, forwardRealFFT.Waveform); var windowRange = MatlabFunctions.MatlabRound(2.0 * fs / currentF0) * 2; var power = Math.Sqrt(forwardRealFFT.Waveform.Take(windowRange).Sum((w) => w * w)); for (var i = 0; i <= windowRange; i++) { forwardRealFFT.Waveform[i] /= power; } FFT.Execute(forwardRealFFT.ForwardFFT); var tmpSpectrum = new Complex[fftSize / 2 + 1]; Array.Copy(forwardRealFFT.Spectrum, tmpSpectrum, tmpSpectrum.Length); for (var i = 0; i < fftSize; i++) { forwardRealFFT.Waveform[i] *= i + 1.0; } FFT.Execute(forwardRealFFT.ForwardFFT); var spectrum = forwardRealFFT.Spectrum; for (int i = 0, limit = fftSize / 2; i <= limit; i++) { centroid[i] = spectrum[i].Real * tmpSpectrum[i].Real + spectrum[i].Imaginary * tmpSpectrum[i].Imaginary; } }
//----------------------------------------------------------------------------- // SetParametersForGetWindowedWaveform() //----------------------------------------------------------------------------- void SetParametersForGetWindowedWaveform(int halfWindowLength, int xLength, double currentPosition, int fs, double currentF0, WindowType windowType, double windowLengthRatio, int[] baseIndex, int[] safeIndex, double[] window) { for (var i = -halfWindowLength; i <= halfWindowLength; i++) { baseIndex[i + halfWindowLength] = i; } var origin = MatlabFunctions.MatlabRound(currentPosition * fs + 0.001); for (int i = 0, limit = halfWindowLength * 2; i <= limit; i++) { safeIndex[i] = Math.Min(xLength - 1, Math.Max(0, origin + baseIndex[i])); } switch (windowType) { case WindowType.Hanning: for (int i = 0, limit = halfWindowLength * 2; i <= limit; i++) { var position = (2.0 * baseIndex[i] / windowLengthRatio) / fs; window[i] = 0.5 * Math.Cos(Math.PI * position * currentF0) + 0.5; } break; case WindowType.Blackman: for (int i = 0, limit = halfWindowLength * 2; i <= limit; i++) { var position = (2.0 * baseIndex[i] / windowLengthRatio) / fs; window[i] = 0.42 + 0.5 * Math.Cos(Math.PI * position * currentF0) + 0.08 * Math.Cos(Math.PI * position * currentF0 * 2); } break; } }
void GetAperiodicity(double[] coarseFrequencyAxis, double[] coarseAperiodicity, int numberOfAperiodicities, double[] frequencyAxis, int fftSize, double[] aperiodicity) { MatlabFunctions.Interp1(coarseFrequencyAxis.SubSequence(0, numberOfAperiodicities + 2), coarseAperiodicity, frequencyAxis.SubSequence(0, fftSize / 2 + 1), aperiodicity); for (int i = 0, limit = fftSize / 2; i <= limit; i++) { aperiodicity[i] = Math.Pow(10.0, aperiodicity[i] / 20.0); } }
public static void DCCorrection(double[] input, double f0, int fs, int fftSize, double[] output) { var upperLimit = 2 + (int)(f0 * fftSize / fs); var lowFrequencyReplica = new double[upperLimit]; var lowFrequencyAxis = Enumerable.Range(0, upperLimit).Select((i) => (double)i * fs / fftSize).ToArray(); var upperLimitReplica = upperLimit - 1; MatlabFunctions.Interp1Q(f0 - lowFrequencyAxis[0], -(double)fs / fftSize, input.SubSequence(0, upperLimit + 1), lowFrequencyAxis.SubSequence(0, upperLimitReplica), lowFrequencyReplica); for (var i = 0; i < upperLimitReplica; i++) { output[i] = input[i] + lowFrequencyReplica[i]; } }
//----------------------------------------------------------------------------- // GetPowerSpectrum() calculates the power_spectrum with DC correction. // DC stands for Direct Current. In this case, the component from 0 to F0 Hz // is corrected. //----------------------------------------------------------------------------- void GetPowerSpectrum(int fs, double f0, ForwardRealFFT forwardRealFFT) { var halfWindowLength = MatlabFunctions.MatlabRound(1.5 * fs / f0); // FFT Array.Clear(forwardRealFFT.Waveform, halfWindowLength * 2 + 1, FFTSize - halfWindowLength * 2 - 1); FFT.Execute(forwardRealFFT.ForwardFFT); var powerSpectrum = forwardRealFFT.Waveform; var spectrum = forwardRealFFT.Spectrum; for (int i = 0, limit = FFTSize / 2; i <= limit; i++) { powerSpectrum[i] = spectrum[i].Real * spectrum[i].Real + spectrum[i].Imaginary * spectrum[i].Imaginary; } Common.DCCorrection(powerSpectrum, f0, fs, FFTSize, powerSpectrum); }
//----------------------------------------------------------------------------- // GetPeriodicResponse() calculates an aperiodic response. //----------------------------------------------------------------------------- void GetPeriodicResponse(int fftSize, double[] spectrum, double[] aperiodicRatio, double currentVUV, double[] periodicResponse) { if (currentVUV <= 0.5 || aperiodicRatio[0] > 0.999) { periodicResponse.Fill(0.0, 0, fftSize); return; } var logSpectrum = MinimumPhase.LogSpectrum; for (int i = 0, limit = MinimumPhase.FFTSize / 2; i <= limit; i++) { logSpectrum[i] = Math.Log(spectrum[i] * (1.0 - aperiodicRatio[i]) + SafeGuardMinimum) / 2.0; } Common.GetMinimumPhaseSpectrum(MinimumPhase); Array.Copy(MinimumPhase.MinimumPhaseSpectrum, 0, InverseRealFFT.Spectrum, 0, fftSize / 2 + 1); FFT.Execute(InverseRealFFT.InverseFFT); MatlabFunctions.FFTShift(InverseRealFFT.Waveform.SubSequence(0, fftSize), periodicResponse); RemoveDCComponent(periodicResponse, fftSize, DCRemover, periodicResponse); }
int GetTimeBase(double[] f0, int f0Length, int fs, double framePeriod, int yLength, double lowestF0, double[] pulseLocations, int[] pulseLocationsIndex, double[] pulseLocationsTimeShift, double[] interpolatedVUV) { var timeAxis = new double[yLength]; var coarseTimeAxis = new double[f0Length + 1]; var coarseF0 = new double[f0Length + 1]; var coarseVUV = new double[f0Length + 1]; GetTemporalParametersForTimeBase(f0, f0Length, fs, yLength, framePeriod, lowestF0, timeAxis, coarseTimeAxis, coarseF0, coarseVUV); var interpolatedF0 = new double[yLength]; MatlabFunctions.Interp1(coarseTimeAxis, coarseF0, timeAxis, interpolatedF0); MatlabFunctions.Interp1(coarseTimeAxis, coarseVUV, timeAxis, interpolatedVUV); for (var i = 0; i < yLength; i++) { interpolatedVUV[i] = interpolatedVUV[i] > 0.5 ? 1.0 : 0.0; interpolatedF0[i] = interpolatedVUV[i] == 0.0 ? DefaultF0 : interpolatedF0[i]; } return(GetPulseLocationsForTimeBase(interpolatedF0, timeAxis, yLength, fs, pulseLocations, pulseLocationsIndex, pulseLocationsTimeShift)); }
double D4CLoveTrainSub(double[] x, int fs, double currentF0, double currentPosition, int f0Length, int fftSize, int boundary0, int boundary1, int boundary2, ForwardRealFFT forwardRealFFT) { var powerSpectrum = new double[fftSize]; var windowLength = MatlabFunctions.MatlabRound(1.5 * fs / currentF0) * 2 + 1; GetWindowedWaveform(x, fs, currentF0, currentPosition, WindowType.Blackman, 3.0, forwardRealFFT.Waveform); Array.Clear(forwardRealFFT.Waveform, windowLength, fftSize - windowLength); FFT.Execute(forwardRealFFT.ForwardFFT); var spectrum = forwardRealFFT.Spectrum; for (int i = boundary0 + 1, limit = fftSize / 2 + 1; i < limit; i++) { powerSpectrum[i] = spectrum[i].Real * spectrum[i].Real + spectrum[i].Imaginary * spectrum[i].Imaginary; } for (var i = boundary0; i <= boundary2; i++) { powerSpectrum[i] += powerSpectrum[i - 1]; } return(powerSpectrum[boundary1] / powerSpectrum[boundary2]); }
//----------------------------------------------------------------------------- // GetWindowedWaveform() windows the waveform by F0-adaptive window // In the variable window_type, 1: hanning, 2: blackman //----------------------------------------------------------------------------- void GetWindowedWaveform(double[] x, int fs, double currentF0, double currentPosition, WindowType windowType, double windowLengthRatio, double[] waveform) { var halfWindowLength = MatlabFunctions.MatlabRound(windowLengthRatio * fs / currentF0 / 2.0); var baseIndex = new int[halfWindowLength * 2 + 1]; var safeIndex = new int[halfWindowLength * 2 + 1]; var window = new double[halfWindowLength * 2 + 1]; SetParametersForGetWindowedWaveform(halfWindowLength, x.Length, currentPosition, fs, currentF0, windowType, windowLengthRatio, baseIndex, safeIndex, window); for (int i = 0, limit = halfWindowLength * 2; i <= limit; i++) { waveform[i] = x[safeIndex[i]] * window[i] + Rand.Next() * SafeGuardMinimum; } var tmpWeight1 = waveform.Sum(); var tmpWeight2 = window.Sum(); var weightingCoefficient = tmpWeight1 / tmpWeight2; for (int i = 0, limit = halfWindowLength * 2; i <= limit; i++) { waveform[i] -= window[i] * weightingCoefficient; } }