Phase 1: Audio Processing & Streaming · 45 min · Python · scipy · libsamplerate
Audio Resampling and Format Conversion
Resampling is where audio quality lives or dies. Get it wrong and your ASR accuracy drops 20%.
Real-world application: Resampling quality directly impacts ASR accuracy — a measurable engineering decision.
What you will learn
- Resample audio between sample rates without introducing artifacts
- Use scipy.signal.resample and libsamplerate for high-quality resampling
- Build the μ-law 8kHz → PCM 16kHz/24kHz conversion pipeline
- Handle edge cases: clipping, aliasing, DC offset
The Problem
Telephony audio arrives at 8kHz. ASR needs 16kHz. TTS outputs 24kHz. WebRTC wants 48kHz. Every transition requires resampling — and bad resampling introduces artifacts that degrade ASR accuracy and audio quality.
The most common resampling bug: aliasing. When downsampling without a low-pass filter, high frequencies fold back into the audible range as artifacts. The audio sounds "metallic" or "underwater."
The Concept
Why Resampling Is Needed
The Nyquist Theorem and Aliasing
The Nyquist theorem states: to represent a frequency f, you need a sample rate of at least 2f. If you downsample from 48kHz to 16kHz without filtering, frequencies above 8kHz (the new Nyquist) will alias — fold back into the 0-8kHz range as false frequencies.
You're downsampling from 48kHz to 8kHz. What happens to a 10kHz tone in the audio?
Aliasing: a 10kHz tone in 48kHz audio, when downsampled to 8kHz without filtering, folds around the new Nyquist frequency (4kHz for 8kHz sample rate). 10kHz → 8000 - (10000 - 8000) = 6000Hz. Actually, the Nyquist for 8kHz is 4kHz, so 10kHz folds to |10000 - 2*4000| = 2000Hz. The fix: apply a low-pass filter at 4kHz before downsampling to remove all frequencies above the new Nyquist.
Upsampling vs Downsampling
| Direction | Risk | Solution |
|---|
| Upsampling (8kHz → 16kHz) | No aliasing (more room) | Interpolation (linear, sinc) |
| Downsampling (48kHz → 16kHz) | Aliasing | Low-pass filter + decimation |
Resampling Methods
| Method | Quality | Speed | Use Case |
|---|
| Linear interpolation | Fair | Fast | Quick prototyping |
scipy.signal.resample | Good | Medium | General purpose (FFT-based) |
scipy.signal.resample_poly | Good | Fast | Polyphase filtering |
| libsamplerate (secret rabbit) | Excellent | Fast | Production quality |
| SoX resampling | Excellent | Medium | Offline processing |
Anti-Aliasing Filter
Before downsampling, apply a low-pass filter at the target Nyquist frequency:
from scipy.signal import resample_poly, butter, sosfilt
def resample_with_antialias(audio, from_rate, to_rate):
if from_rate == to_rate:
return audio
if to_rate < from_rate:
# Downsampling: apply anti-aliasing filter
cutoff = to_rate / 2 # New Nyquist
sos = butter(10, cutoff / (from_rate / 2), output='sos')
audio = sosfilt(sos, audio.astype(np.float32))
# Use polyphase resampling
from scipy.signal import resample_poly
gcd = np.gcd(from_rate, to_rate)
up = to_rate // gcd
down = from_rate // gcd
return resample_poly(audio, up, down).astype(np.int16)
Unlock the full lesson
You've read the first 2 sections. The rest of this lesson covers Build, Check Yourself, Key Terms & Next — plus a hands-on lab, quiz, and project artifact.
Create a free account — the opening phases of 29 of 35 courses are free, no credit card.
Browse all courses · View pricing · DeVenture Academy