Closed Sorseg closed 11 hours ago
Very interesting. I came up with a novel idea for a synth, basically because I assumed I will never in my life find out how to properly align phases in resynth. I am glad I didn't find your post two weeks ago, because then I would probably just have fixed my wavetables with pitch-shift. That does not mean that pitch-shift will not be handy in the future. Thanks!
Hi! Thanks for the snippet. I think you understood the interface just fine, probably better than me. I'm closing this but open another issue if you still have questions.
Hi! I've managed to implement a pitch-shifter that sounds decently to me, using the "phase vocoder" approach, nicely explained in this youtube playlist. The
resynth
node was a great timesaver!However I am not fully grokking the
fundsp
API so I could use some help with the PR.The whole code, provided by me under CC0
```rust let pitch_shift = 0.8_f32; const FRAME_SIZE: usize = 512 * 2; // FIXME: these should probably be of size `FRAME_SIZE/2 + 1` let mut input_phases = [0.0; FRAME_SIZE]; let mut incoming_frequencies = [0.0; FRAME_SIZE]; let mut outgoing_phases = [0.0; FRAME_SIZE]; let bin_width = rec_sample_rate as f32 / FRAME_SIZE as f32; // copy-pasted from the resynth const WINDOWS: usize = 4; // how much time passes between the resynth calls let dt = FRAME_SIZE as f32 / pb_sample_rate as f32 / WINDOWS as f32; let pitch_shift = resynth::(FRAME_SIZE, move |fft: &mut FftWindow| {
for i in 0..(fft.bins() - 1) {
let freq = fft.frequency(i);
// phase [-pi, pi]
let (amplitude, phase) = fft.at(0, i).to_polar();
// [0, tau)
let phase_delta = (phase - input_phases[i] + TAU) % TAU;
// [0, tau)
let expected_phase_d = freq * dt * TAU % TAU;
// [-pi, pi)
let phase_error = (phase_delta - expected_phase_d) % PI;
// phase offset to frequency
let freq_deviation = phase_error / TAU / dt;
let bin_deviation = freq_deviation / bin_width;
incoming_frequencies[i] = i as f32 + bin_deviation;
input_phases[i] = phase;
// calc output
let newbin = (i as f32 * pitch_shift).round() as usize;
if newbin > 0 && newbin < fft.bins() {
let bin_deviation = incoming_frequencies[i] * pitch_shift - newbin as f32;
let freq = bin_deviation * bin_width + fft.frequency(newbin);
let phase_diff = freq * dt * TAU;
let out_phase = (outgoing_phases[newbin] + phase_diff) % TAU;
fft.set(0, newbin, Complex32::from_polar(amplitude, out_phase));
outgoing_phases[newbin] = out_phase;
}
}
});
```
Used in this voice changer project https://github.com/Sorseg/combiner/tree/master