bmcfee / pyrubberband

python wrapper for rubberband
ISC License
154 stars 20 forks source link

Low sample rate signal hang with rubberband #13

Open markostam opened 6 years ago

markostam commented 6 years ago

I've noticed that when you try to use rubberband on very low-samplerate signals (anything 210Hz and below) rubberband will hang.

These both hang:

y = np.random.rand(1024)

shifted = pyrubberband.pitch_shift(y=y, sr=210, n_steps=2)
stretched = pyrubberband.time_stretch(y=y, sr=210, rate=0.5)

These both work

y = np.random.rand(1024)

shifted = pyrubberband.pitch_shift(y=y, sr=211, n_steps=2)
stretched = pyrubberband.time_stretch(y=y, sr=211, rate=0.5)

The rubberband CLI has the same behavior; it hangs during the first studying pass at 99% CPU until you send it a break:

$ rubberband -d3 -t 2.0 /tmp/tmpzGl2Zt.wav /tmp/tmpzGl2Zt_2.wav
Using crispness level: 5 (Crisp monophonic instrumental)
Using time ratio 2 and frequency ratio 1
RubberBandStretcher::Impl::Impl: rate = 125, options = 16
configure: effective ratio = 2
configure: analysis window size = 8, synthesis window size = 8, fft size = 8, increment = 0 (approx output increment = 0)
configure: outbuf size = 8192
Window area: 0.5; synthesis window area: 0.5
FFT::FFT(8): using implementation: fftw
Not real time mode: prefilling
configure: effective ratio = 2
configure: analysis window size = 8, synthesis window size = 8, fft size = 8, increment = 0 (approx output increment = 0)
configure: outbuf size = 8192
Not real time mode: prefilling
configure: effective ratio = 2
configure: analysis window size = 8, synthesis window size = 8, fft size = 8, increment = 0 (approx output increment = 0)
configure: outbuf size = 8192
Pass 1: Studying...

Interestingly, this only seems to be an issue when rate for time_stretch < 1 or when n_steps for pitch_shift > 0, otherwise it runs fine.

I haven't had time to dig into the rubberband source and likely will not any time soon but I've noticed that passing the --window-long flag will allow it to run to completion. IE these both run fine:

y = np.random.rand(1024)

shifted = pyrubberband.pitch_shift(y=y, sr=210, n_steps=2, rbargs={"-q":"--window-long"})
stretched = pyrubberband.time_stretch(y=y, sr=210, rate=0.5, rbargs={"-q":"--window-long"})

It's hacky, but would it make sense to simply add a conditional that would add the --window-long flag to any sr <= 210?