nc-murray/spectrogram-reconstruction
0
1"""Tests for reconstructor.py — verify Griffin-Lim produces non-silent audio."""2 3import numpy as np4import pytest5import librosa6import sys, os7sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))8 9from specrec.reconstructor import reconstruct_audio10 11 12def _make_magnitude(sr=22050, n_fft=2048, hop_length=512, duration=1.0):13 """Programmatic magnitude spectrogram — bypasses image parsing."""14 t = np.linspace(0, duration, int(sr * duration), endpoint=False)15 tone = (0.5 * np.sin(2 * np.pi * 440 * t)).astype(np.float32)16 S = np.abs(librosa.stft(tone, n_fft=n_fft, hop_length=hop_length))17 return S, tone18 19 20def test_reconstruct_audio_non_silent():21 S, _ = _make_magnitude()22 audio = reconstruct_audio(S, n_iter=10)23 assert audio.ndim == 124 rms = np.sqrt(np.mean(audio ** 2))25 assert rms > 1e-4, f"Output is silent (RMS={rms})"26 27 28def test_reconstruct_audio_correct_length():29 sr, n_fft, hop_length, duration = 22050, 2048, 512, 1.030 S, _ = _make_magnitude(sr=sr, n_fft=n_fft, hop_length=hop_length, duration=duration)31 audio = reconstruct_audio(S, sr=sr, n_fft=n_fft, hop_length=hop_length, n_iter=10)32 expected = int(sr * duration)33 # Griffin-Lim output length is close to original but may differ by a few samples34 assert abs(len(audio) - expected) < hop_length * 2, (35 f"Length {len(audio)} far from expected {expected}"36 )37 38 39def test_reconstruct_audio_dtype():40 S, _ = _make_magnitude()41 audio = reconstruct_audio(S, n_iter=5)42 assert audio.dtype == np.float3243 44 45def test_reconstruct_audio_dominant_frequency():46 sr, n_fft, hop_length = 22050, 2048, 51247 S, _ = _make_magnitude(sr=sr, n_fft=n_fft, hop_length=hop_length, duration=2.0)48 audio = reconstruct_audio(S, sr=sr, n_fft=n_fft, hop_length=hop_length, n_iter=60)49 fft = np.abs(np.fft.rfft(audio))50 freqs = np.fft.rfftfreq(len(audio), 1 / sr)51 peak_freq = freqs[np.argmax(fft)]52 assert abs(peak_freq - 440.0) < 5.0, f"Dominant freq {peak_freq:.1f} Hz, expected ~440 Hz"53 