| |
| """ |
| 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) |
|
|
| |
| sos = signal.butter(4, args.highpass, btype="highpass", fs=sr, output="sos") |
| y = signal.sosfilt(sos, y) |
|
|
| |
| y = nr.reduce_noise(y=y, sr=sr, prop_decrease=args.gate, stationary=True) |
|
|
| |
| 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() |
|
|