coda / test_app_logic.py
blackboxanalytics's picture
Rebuild CODA on Stable Audio 3 Small Music
e8b2f06
Raw
History Blame Contribute Delete
3.51 kB
"""Tests for app.py wiring: on-upload analysis, demo loading, and the full
finish_song pipeline with the SA3 engine stubbed (no GPU, no weights). Verifies
the real DSP (analyze, enhance, stitch) runs end-to-end on the bundled demo and
produces a valid 44.1 kHz stereo file. Skips if gradio isn't installed."""
import os
import numpy as np
import pytest
import soundfile as sf
pytest.importorskip("gradio")
import app # noqa: E402
import engine # noqa: E402
DEMO = app.PUSHBACK_DEMO
_HAVE_DEMO = os.path.exists(DEMO)
need_demo = pytest.mark.skipif(not _HAVE_DEMO, reason="bundled demo clip absent")
class _Prog:
"""stand-in for gr.Progress — records the (frac, desc) stages it's told."""
def __init__(self):
self.calls = []
def __call__(self, frac, desc=None):
self.calls.append((frac, desc))
@need_demo
def test_load_demo_returns_clip():
assert app.load_demo() == DEMO
assert os.path.exists(DEMO)
@need_demo
def test_analyze_on_upload_reports_and_enables():
info_update, btn_update = app.analyze_on_upload(DEMO)
md = info_update["value"]
assert "KEY" in md and "TEMPO" in md and "BPM" in md
assert info_update["visible"] is True
assert btn_update["interactive"] is True
def test_analyze_on_upload_empty_disables_button():
_, btn_update = app.analyze_on_upload(None)
assert btn_update["interactive"] is False
@need_demo
def test_finish_song_pipeline_with_stubbed_engine(monkeypatch):
"""stub engine.continue_audio with a fast synthetic tail; the rest of the
pipeline (enhance, analyze, stitch, write) runs for real."""
def fake_continue_audio(clip_path, total_seconds, prompt="", progress=None,
**kw):
if progress:
progress("reading")
progress("composing")
progress("finalizing")
new_secs = total_seconds - 29.53 # demo is ~29.53s
n = int(max(new_secs, 5) * engine.SR)
t = np.arange(n) / engine.SR
wave = 0.2 * np.sin(2 * np.pi * 220 * t).astype(np.float32)
tail = np.stack([wave, wave])
return tail, 29.53, engine.SR
monkeypatch.setattr(engine, "continue_audio", fake_continue_audio)
prog = _Prog()
out_path, summary = app.finish_song(DEMO, 60, "", False, progress=prog)
assert os.path.exists(out_path)
y, sr = sf.read(out_path)
assert sr == 44100
assert y.ndim == 2 and y.shape[1] == 2 # 44.1k stereo
assert len(y) / sr > 50 # ~60s finished
assert float(np.abs(y).max()) <= 1.0
assert float(np.sqrt(np.mean(y ** 2))) > 1e-3 # not silent
assert "BPM" in summary and "Stable Audio 3" in summary
# progress streamed several stages and ended at 100%
assert len(prog.calls) >= 4
assert prog.calls[-1][0] == 1.0
@need_demo
def test_finish_song_remaster_path(monkeypatch):
def fake_continue_audio(clip_path, total_seconds, prompt="", progress=None,
**kw):
n = int(15 * engine.SR)
wave = 0.2 * np.sin(2 * np.pi * 220 * np.arange(n) / engine.SR)
return np.stack([wave, wave]).astype(np.float32), 29.53, engine.SR
monkeypatch.setattr(engine, "continue_audio", fake_continue_audio)
out_path, _ = app.finish_song(DEMO, 45, "", True, progress=_Prog())
assert os.path.exists(out_path)
def test_finish_song_rejects_empty_input():
with pytest.raises(Exception):
app.finish_song(None, 60, "", False, progress=_Prog())