Spaces:
Running on Zero
Running on Zero
| """input enhancement: coda hears the song, not the noise. | |
| people's unfinished songs live on phone recordings, voice memos, old mp3 | |
| rips — low level, hissy, rumbly. feeding that straight to musicgen makes | |
| the model imitate the *recording* (artifacts included) instead of the | |
| *music*. this module cleans the copy of the input that feeds analysis and | |
| the audio prompt: high-pass the rumble, spectrally gate the steady noise | |
| floor, normalize the level. the user's untouched original still goes into | |
| the final track (unless they choose remaster mode, which runs the same | |
| cleanup on the original before the splice). | |
| deliberately gentle, deliberately DSP-only: a denoiser that invents | |
| content would be another model to fight. nothing here changes the length | |
| or timing of the audio — the sample-aligned crossfade math downstream | |
| depends on that. | |
| """ | |
| import os | |
| import tempfile | |
| import librosa | |
| import numpy as np | |
| import soundfile as sf | |
| from scipy.signal import butter, filtfilt | |
| # below this the input gets flagged as lo-fi in the ui | |
| LOFI_BANDWIDTH_HZ = 13000 | |
| LOFI_NOISE_DB = -38.0 | |
| N_FFT = 2048 | |
| HOP = 512 | |
| def _highpass(y, sr, cutoff=35.0): | |
| """rumble filter. filtfilt = zero phase shift, length preserved.""" | |
| b, a = butter(2, cutoff / (sr / 2), btype="high") | |
| return filtfilt(b, a, y, axis=-1).astype(np.float32) | |
| def _gate_channel(y, sr, reduction_db=12.0, percentile=10): | |
| """ | |
| spectral gating on one channel: estimate the per-band noise floor from | |
| the quietest frames, then softly attenuate anything near that floor. | |
| musical content sits well above the floor and passes untouched. | |
| """ | |
| spec = librosa.stft(y, n_fft=N_FFT, hop_length=HOP) | |
| mag = np.abs(spec) | |
| frame_energy = mag.mean(axis=0) | |
| quiet = mag[:, frame_energy <= np.percentile(frame_energy, percentile)] | |
| if quiet.shape[1] < 2: # uniformly loud clip — nothing to learn from | |
| return y | |
| noise_profile = np.median(quiet, axis=1, keepdims=True) | |
| # soft mask: 1 well above the floor, floor_gain at/below it | |
| floor_gain = 10 ** (-reduction_db / 20) | |
| ratio = mag / (noise_profile * 2.0 + 1e-10) | |
| mask = np.clip((ratio - 1.0) / 2.0, 0.0, 1.0) | |
| mask = floor_gain + (1.0 - floor_gain) * mask | |
| out = librosa.istft(spec * mask, n_fft=N_FFT, hop_length=HOP, | |
| length=len(y)) | |
| return out.astype(np.float32) | |
| def enhance_audio(y, sr, normalize=True): | |
| """ | |
| high-pass + spectral gate + peak normalize. accepts 1-D (mono) or | |
| 2-D (channels, samples) float32; returns the same shape and length. | |
| gentle on clean input — a quiet clip just gets lifted to level. | |
| """ | |
| orig_ndim = np.asarray(y).ndim | |
| y = np.atleast_2d(np.asarray(y, dtype=np.float32)) | |
| out = _highpass(y, sr) | |
| out = np.stack([_gate_channel(ch, sr) for ch in out]) | |
| if normalize: | |
| peak = float(np.abs(out).max()) | |
| if peak > 1e-6: | |
| out = out * (0.891 / peak) # -1 dBFS | |
| out = out.astype(np.float32) | |
| return out if orig_ndim == 2 else out[0] | |
| def enhance_to_tempfile(path): | |
| """ | |
| enhanced copy of `path` written as wav, for the analysis + musicgen | |
| prompt feed. returns the new path; falls back to the original path if | |
| anything goes sideways — enhancement must never block the pipeline. | |
| """ | |
| try: | |
| y, sr = librosa.load(path, sr=None, mono=False) | |
| cleaned = enhance_audio(y, sr) | |
| out_path = os.path.join(tempfile.mkdtemp(), "coda_enhanced.wav") | |
| sf.write(out_path, cleaned.T if cleaned.ndim == 2 else cleaned, sr) | |
| return out_path | |
| except Exception as e: | |
| print(f"[coda] enhancement failed ({e}); using raw input", flush=True) | |
| return path | |
| def input_quality(path): | |
| """ | |
| judge the recording (not the song): effective bandwidth and noise | |
| floor. returns {"bandwidth_hz", "noise_db", "lofi"} or None on failure. | |
| """ | |
| try: | |
| y, sr = librosa.load(path, sr=None, mono=True) | |
| if len(y) < sr: | |
| return None | |
| mag = np.abs(librosa.stft(y, n_fft=4096)) | |
| med = np.median(mag, axis=1) | |
| ref = float(med.max()) | |
| if ref <= 0: | |
| return None | |
| above = np.where(med > ref * 10 ** (-55 / 20))[0] | |
| freqs = librosa.fft_frequencies(sr=sr, n_fft=4096) | |
| bandwidth = float(freqs[above[-1]]) if len(above) else 0.0 | |
| frames = librosa.util.frame(y, frame_length=2048, hop_length=1024) | |
| frame_rms = np.sqrt(np.mean(frames ** 2, axis=0)) | |
| noise_db = float(20 * np.log10(np.percentile(frame_rms, 10) + 1e-12)) | |
| return { | |
| "bandwidth_hz": round(bandwidth), | |
| "noise_db": round(noise_db, 1), | |
| "lofi": bandwidth < LOFI_BANDWIDTH_HZ or noise_db > LOFI_NOISE_DB, | |
| } | |
| except Exception as e: | |
| print(f"[coda] quality probe failed ({e})", flush=True) | |
| return None | |