public PhaseVocoder(int Pt, int Qt, int Pp, int Qp, bool robotoFX, int winLength) { this.Qt = Qt; this.Pt = Pt; this.Qp = Qp; this.Pp = Pp; this.robotoFX = robotoFX; tfr = new TFR(); stft = new STFT(winLength); resampler = new Resample.Resampler((uint)Qp, (uint)Pp); }
/* * Pt/Qt = tempo change factor. A tempo change factor < 1 will lead to slower tempo. A tempo change factor > 1 will lead to faster tempo * Pp/Qp = pitch shift factor. A pitch shift factor < 1 will lead to reduced/lower pitch. A pitch shift factor > 1 will lead to increased/raised pitch. * */ public PhaseVocoder(int Pt, int Qt, int Pp, int Qp) { this.Qt = Qt; this.Pt = Pt; this.Qp = Qp; this.Pp = Pp; this.robotoFX = false; tfr = new TFR(); stft = new STFT(128); resampler = new Resample.Resampler((uint)Qp, (uint)Pp); }
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); }
public double[] inverse(TFR tfr) { int nf = tfr.getTFRAsDoubleArray().Length - 1; int nw = tfr.getTFRAsDoubleArray()[0].Length; int ns = nf * hopSize + nw; double[] output = new double[ns]; fftw_complexarray mdin = new fftw_complexarray(nw); fftw_complexarray mdout = new fftw_complexarray(nw); fftw_plan plan; int hopInd = 0; Complex[] buf = new Complex[nw]; try { for (int hop = 0; hop <= nf * hopSize; hop += hopSize) { mdout.SetData(buf); mdin.SetData(tfr.getTFRAsDoubleArray()[hopInd++]); plan = fftw_plan.dft_1d(winLength, mdin, mdout, fftw_direction.Backward, fftw_flags.Estimate); plan.Execute(); buf = mdout.GetData_Complex(); for (int sample = 0; sample < nw; sample++) { output[sample + hop] = output[sample + hop] + (buf[sample].Real / nw) * win[sample].Real; } } return(output); } catch (Exception) { return(output); } }
public double[] inverse(TFR tfr, ref double[] output_signal_prev, bool last) { int nf = tfr.getTFRAsDoubleArray().Length - 1; int nw = tfr.getTFRAsDoubleArray()[0].Length; int ns = nf * hopSize + nw; double[] output_signal_tmp = new double[ns]; double[] output_signal = new double[output_signal_tmp.Length - 3 * hopSize]; fftw_complexarray mdin = new fftw_complexarray(nw); fftw_complexarray mdout = new fftw_complexarray(nw); fftw_plan plan; if (output_signal_prev == null) { output_signal_prev = new double[3 * hopSize]; } for (int sample = 0; sample < hopSize * 3; sample++) { output_signal_tmp[sample] = output_signal_prev[sample]; } int hopInd = 0; Complex[] buf = new Complex[nw]; try { for (int hop = 0; hop <= nf * hopSize; hop += hopSize) { mdout.SetData(buf); mdin.SetData(tfr.getTFRAsDoubleArray()[hopInd++]); plan = fftw_plan.dft_1d(winLength, mdin, mdout, fftw_direction.Backward, fftw_flags.Estimate); plan.Execute(); buf = mdout.GetData_Complex(); for (int sample = 0; sample < nw; sample++) { output_signal_tmp[sample + hop] = output_signal_tmp[sample + hop] + (buf[sample].Real / nw) * win[sample].Real; } } for (int sample = 0; sample < hopSize * 3; sample++) { output_signal_prev[sample] = output_signal_tmp[output_signal_tmp.Length - hopSize * 3 + sample]; } for (int sample = 0; sample < output_signal.Length; sample++) { output_signal[sample] = output_signal_tmp[sample]; } if (last) { return(output_signal_tmp); } else { return(output_signal); } } catch (Exception) { if (last) { return(output_signal_tmp); } else { return(output_signal); } } }