aboutsummaryrefslogtreecommitdiff
path: root/lib/tests/conftest.py
blob: 885d22bf49145bf38df50248fb899f31fac90712 (plain)
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
from __future__ import annotations

import sys
from pathlib import Path

import numpy as np
import pytest

SRC = Path(__file__).resolve().parents[1] / "src"
sys.path.insert(0, str(SRC))
sys.path.insert(0, str(Path(__file__).resolve().parent))

SR = 44100


def speechish(
    dur: float,
    sr: int = SR,
    level_dbfs: float = -20.0,
    seed: int = 0,
) -> np.ndarray:
    rng = np.random.default_rng(seed)
    n = int(sr * dur)
    t = np.arange(n) / sr
    f0 = 110.0 * (1.0 + 0.02 * np.sin(2 * np.pi * 0.9 * t))
    phase = 2 * np.pi * np.cumsum(f0) / sr
    x = np.zeros(n)
    for k in range(1, 9):
        x += (1.0 / k**1.3) * np.sin(k * phase + 0.3 * k)
    syll = 0.5 + 0.5 * np.sin(2 * np.pi * 3.0 * t + float(rng.uniform(0, 6)))
    pauses = (np.sin(2 * np.pi * 0.5 * t) > -0.6).astype(float)
    env = np.clip(syll, 0.02, 1.0) ** 0.6 * np.maximum(pauses, 0.05)
    x = x * env
    x /= np.max(np.abs(x)) + 1e-12
    return (x * (10 ** (level_dbfs / 20.0))).astype(np.float32)


def sine(freq: float, dur: float, sr: int = SR, peak_dbfs: float = -20.0) -> np.ndarray:
    t = np.arange(int(sr * dur)) / sr
    return (10 ** (peak_dbfs / 20.0) * np.sin(2 * np.pi * freq * t)).astype(np.float32)


def band_db(x: np.ndarray, sr: int, lo: float, hi: float) -> float:
    from scipy import signal

    sos = signal.butter(4, [lo, hi], btype="bandpass", fs=sr, output="sos")
    y = signal.sosfilt(sos, x.astype(np.float64))
    r = np.sqrt(np.mean(np.square(y)))
    if r <= 0:
        return -120.0
    return float(20 * np.log10(r))


@pytest.fixture
def sr() -> int:
    return SR


@pytest.fixture
def speech() -> np.ndarray:
    return speechish(6.0, level_dbfs=-20.0)


@pytest.fixture
def noisy_speech(sr, speech) -> np.ndarray:
    rng = np.random.default_rng(7)
    noise = rng.standard_normal(speech.size)
    noise *= (10 ** (-48.0 / 20.0)) / np.sqrt(np.mean(np.square(noise)))
    hum = 0.003 * np.sin(2 * np.pi * 50.0 * np.arange(speech.size) / sr)
    return (speech + noise + hum).astype(np.float32)