jam-buddy / tools /clean_beatbox.py
salgadev's picture
Sync from GitHub 6feaf31d
b2e4883 verified
Raw
History Blame Contribute Delete
1.6 kB
#!/usr/bin/env python3
"""
Clean a beatbox recording before SA3: high-pass fan rumble + spectral-gate hiss.
The audio-to-audio path preserves the input's structure, so a noisy beatbox
(fan rumble, headset hiss) carries its noise straight into the output. This
preprocesses the input so SA3 only sees the beatbox's rhythmic content.
Usage:
.venv/Scripts/python.exe tools/clean_beatbox.py --in raw.wav --out clean.wav
"""
import argparse
import noisereduce as nr
import numpy as np
import soundfile as sf
from scipy import signal
def main():
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("--in", dest="src", required=True)
ap.add_argument("--out", required=True)
ap.add_argument("--highpass", type=float, default=80.0,
help="high-pass cutoff Hz (fan rumble)")
ap.add_argument("--gate", type=float, default=0.5,
help="noise-reduction strength 0-1")
args = ap.parse_args()
y, sr = sf.read(args.src)
if y.ndim > 1:
y = y.mean(axis=1) # mono for processing
# 1. High-pass to kill fan/rumble below cutoff
sos = signal.butter(4, args.highpass, btype="highpass", fs=sr, output="sos")
y = signal.sosfilt(sos, y)
# 2. Spectral-gate the stationary hiss (noisereduce)
y = nr.reduce_noise(y=y, sr=sr, prop_decrease=args.gate, stationary=True)
# 3. Normalize to a healthy level
peak = np.abs(y).max()
if peak > 0:
y = y / peak * 0.9
sf.write(args.out, y, sr)
print(f"Wrote {args.out}: {len(y)/sr:.1f}s, sr={sr}")
if __name__ == "__main__":
main()