File size: 3,557 Bytes
e8b2f06
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
"""Unit tests for verify.py — the math QA metrics. Builds synthetic finished
tracks (good, silence-collapsed, clipped) as temp WAVs and checks the right
metric catches each fault. No model needed."""
import numpy as np
import soundfile as sf

import verify

SR = verify.SR


def _stereo(freqs, seconds, amp=0.3):
    """sum of sine partials -> a richer (non-pure-tone) stereo signal."""
    t = np.arange(int(seconds * SR)) / SR
    y = sum(np.sin(2 * np.pi * f * t) for f in freqs) / len(freqs)
    L = (amp * y).astype(np.float32)
    R = (amp * np.roll(y, 13)).astype(np.float32)   # slight decorrelation
    return np.stack([L, R])


def _write(path, audio):
    sf.write(str(path), audio.T, SR, subtype="PCM_16")


def test_relative_keys():
    assert "A minor" in verify._relative_keys("C major")
    assert "C major" in verify._relative_keys("A minor")
    assert "C major" in verify._relative_keys("C major")


def test_good_continuation_passes_health_metrics(tmp_path):
    chord = [220, 277, 330]                          # A major-ish triad
    orig = _stereo(chord, 10)
    finished = _stereo(chord, 40)                    # continuous, same content
    op, fp = tmp_path / "o.wav", tmp_path / "f.wav"
    _write(op, orig)
    _write(fp, finished)
    rep = verify.verify(str(op), str(fp), source_seconds=10)
    m = rep["metrics"]
    assert m["no_silence_collapse"]["pass"]
    assert m["no_clipping"]["pass"]
    assert m["duration"]["pass"]
    assert m["loudness_continuity"]["pass"]
    assert m["spectral_rolloff"]["pass"]


def test_silence_collapse_is_caught(tmp_path):
    chord = [220, 277, 330]
    orig = _stereo(chord, 10)
    new = _stereo(chord, 30)
    new[:, 5 * SR:15 * SR] = 0.0                     # a dead 10s stretch mid-tail
    finished = np.concatenate([_stereo(chord, 10), new], axis=-1)
    op, fp = tmp_path / "o.wav", tmp_path / "f.wav"
    _write(op, orig)
    _write(fp, finished)
    rep = verify.verify(str(op), str(fp), source_seconds=10)
    assert not rep["metrics"]["no_silence_collapse"]["pass"]


def test_clipping_is_caught(tmp_path):
    chord = [220, 277, 330]
    orig = _stereo(chord, 10)
    finished = _stereo(chord, 30) * 4.0              # drive it hard
    finished = np.clip(finished, -1.0, 1.0)          # …into hard clipping
    op, fp = tmp_path / "o.wav", tmp_path / "f.wav"
    _write(op, orig)
    _write(fp, finished)
    rep = verify.verify(str(op), str(fp), source_seconds=10)
    assert not rep["metrics"]["no_clipping"]["pass"]


def test_closing_fade_not_flagged_as_collapse(tmp_path):
    """a real cos^2 closing fade must NOT trip the silence-collapse metric."""
    chord = [220, 277, 330]
    finished = _stereo(chord, 40)
    fade = int(4.0 * SR)
    curve = np.cos(np.linspace(0, np.pi / 2, fade)) ** 2
    finished[:, -fade:] *= curve
    orig = _stereo(chord, 10)
    op, fp = tmp_path / "o.wav", tmp_path / "f.wav"
    _write(op, orig)
    _write(fp, finished)
    rep = verify.verify(str(op), str(fp), source_seconds=10, fade_seconds=4.0)
    assert rep["metrics"]["no_silence_collapse"]["pass"]


def test_report_shape(tmp_path):
    chord = [220, 277, 330]
    op, fp = tmp_path / "o.wav", tmp_path / "f.wav"
    _write(op, _stereo(chord, 10))
    _write(fp, _stereo(chord, 30))
    rep = verify.verify(str(op), str(fp), source_seconds=10)
    assert set(["metrics", "passed", "finished", "boundary"]).issubset(rep)
    assert isinstance(rep["passed"], bool)
    for name, mtr in rep["metrics"].items():
        assert set(["value", "pass", "reason"]).issubset(mtr)