public double[] apply(double[] input_signal) { tfr = stft.forward(input_signal); tfr.applyTempoChange((double)Pt / (double)Qt * (double)Qp / (double)Pp, false, this.robotoFX, ref fi, ref dfi); /* Tempo change step */ double[] output_signal = stft.inverse(tfr); /* Pitch shift step. Apply function resample(Qp, Pp) on output_signal to change its sample rate by a factor Qp/Pp (multiplied by) */ output_signal = resampler.Resample(output_signal); return(output_signal); }
/* For real-time usage, ensure that the output blocks are continuous */ public double[] applyContinuous(double[] input_signal, int Pt, int Qt, int Pp, int Qp, bool robotoFX) { List <double[]> frame = prepFrame(input_signal, prev_input_signal); for (int frameNum = 0; frameNum < frame.Count; frameNum++) { tfr = stft.forward(frame[frameNum]); tfr.applyTempoChange((double)Pt / (double)Qt * (double)Qp / (double)Pp, true, robotoFX, ref fi, ref dfi); /* Tempo change step */ if (input_signal == null) { frame[frameNum] = stft.inverse(tfr, ref prev_output_signal, true); } else { frame[frameNum] = stft.inverse(tfr, ref prev_output_signal, false); } } /* Combine blocks to produce single output block */ double[] output_signal; if (frame.Count == 1) { if (input_signal == null) { output_signal = bondFrames(frame, FRAMETYPE.START); } else { output_signal = bondFrames(frame, FRAMETYPE.END); } } else { output_signal = bondFrames(frame, FRAMETYPE.MID); } if (input_signal != null) { prev_input_signal = new double[input_signal.Length]; for (int sample = 0; sample < input_signal.Length; sample++) { prev_input_signal[sample] = input_signal[sample]; } } /* Pitch shift step. Apply OUTPUT-BLOCK-CONTINUOUS function resampleContinuous(Qp, Pp) on output_signal to change its sample rate by a factor Qp/Pp (multiplied by) */ output_signal = resampler.ResampleContinuous(output_signal); return(output_signal); }