While building a "Voice Design" app, I added a slider to adjust speech rate (speaking speed). The goal was simple: speed up or slow down the tempo without changing the pitch. This is a very common requirement.
librosa has a function called librosa.effects.time_stretch designed exactly for this. It’s a one-liner. That’s what I used at first. However, as soon as I moved the slider even slightly, a faint metallic ringing would appear in the output. The voice sounded slightly "robotic" and "echoey," becoming muffled. The original voice was natural, but the moment the tempo changed, the quality dropped.
This article is a record of how I discovered that the cause was phase blurring in the phase vocoder and how I resolved it by implementing WSOLA (Waveform Similarity Overlap-Add) from scratch using numpy.
Premise: Changing tempo while preserving pitch
If you simply drop or duplicate audio samples, the pitch will shift along with the playback speed (the "chipmunk effect" you get when fast-forwarding). Time stretching is the process of changing only the tempo while avoiding this pitch shift.






