165 lines
4.2 KiB
Python
165 lines
4.2 KiB
Python
# Copyright 2024-2025 XMOS LIMITED.
|
|
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
|
import pytest
|
|
import numpy as np
|
|
from audio_dsp.dsp.reverb_base import Q_VERB
|
|
from audio_dsp.dsp.reverb import reverb_room
|
|
from audio_dsp.dsp.reverb_stereo import reverb_room_stereo
|
|
from audio_dsp.dsp.reverb_plate import reverb_plate_stereo
|
|
from subprocess import run
|
|
from pathlib import Path
|
|
import os
|
|
|
|
CWD = Path(__file__).parent
|
|
TOL_KWARGS = dict(rtol=2**-16, atol=0)
|
|
LESS_THAN_1 = ((2**Q_VERB) - 1) / (2**Q_VERB)
|
|
|
|
|
|
def q_verb(x):
|
|
return int(x * 2**Q_VERB)
|
|
|
|
|
|
def db2lin(db):
|
|
return 10 ** (db / 20)
|
|
|
|
|
|
def new_reverb(**kwargs):
|
|
return reverb_room(48000, 1, **kwargs)
|
|
|
|
|
|
def get_c(config, val):
|
|
bin_dir = CWD / "bin" / config
|
|
out_dir = CWD / "bin" / f"{config}_{val}"
|
|
os.makedirs(out_dir, exist_ok=True)
|
|
sig_fl32 = np.array(val).astype(np.float32)
|
|
name = "test_vector"
|
|
sig_fl32.tofile(out_dir / f"{name}.bin")
|
|
|
|
xe = bin_dir / f"reverb_converters_{config}.xe"
|
|
run(["xsim", str(xe)], check=True, cwd=out_dir)
|
|
#print(out_dir)
|
|
return np.fromfile(out_dir / "out_vector.bin", dtype=np.int32)
|
|
|
|
|
|
def db2int(db):
|
|
return q_verb(db2lin(db))
|
|
|
|
|
|
def get_output(config, input, sattr, gattr):
|
|
c_val = get_c(config, input)[0]
|
|
r = new_reverb()
|
|
setattr(r, sattr, input)
|
|
p_val = getattr(r, gattr)
|
|
return c_val, p_val
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"sattr,gattr",
|
|
[
|
|
["wet_db", "wet_int"],
|
|
["dry_db", "dry_int"],
|
|
],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
"input,expected",
|
|
[
|
|
[-6, db2int(-6)],
|
|
[0, q_verb(1)],
|
|
[1, q_verb(1)],
|
|
[6, q_verb(1)],
|
|
],
|
|
)
|
|
def test_reverb_db2int(sattr, gattr, input, expected):
|
|
np.testing.assert_allclose(
|
|
get_output("DB2INT", input, sattr, gattr), expected, **TOL_KWARGS
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"input,expected",
|
|
[
|
|
[0, q_verb(0.7)],
|
|
[-1, q_verb(0.7)],
|
|
[1, q_verb(0.98)],
|
|
[1.1, q_verb(0.98)],
|
|
],
|
|
)
|
|
def test_reverb_decay2feedback(input, expected):
|
|
np.testing.assert_allclose(
|
|
get_output("DECAY2FEEDBACK", input, "decay", "feedback_int"),
|
|
expected,
|
|
**TOL_KWARGS,
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"input,expected",
|
|
[
|
|
[-0.5, 0],
|
|
[0, 0],
|
|
[0.5, q_verb(0.5)],
|
|
[LESS_THAN_1, q_verb(LESS_THAN_1)],
|
|
[1, q_verb(LESS_THAN_1)],
|
|
[2, q_verb(LESS_THAN_1)],
|
|
],
|
|
)
|
|
def test_reverb_float2int(input, expected):
|
|
np.testing.assert_allclose(
|
|
get_output("FLOAT2INT", input, "pregain", "pregain_int"), expected, **TOL_KWARGS
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"input,expected",
|
|
[
|
|
[-0.5, 1],
|
|
[0, 1],
|
|
[0.5, q_verb(0.5)],
|
|
[LESS_THAN_1, q_verb(LESS_THAN_1)],
|
|
[1, q_verb(LESS_THAN_1)],
|
|
[2, q_verb(LESS_THAN_1)],
|
|
],
|
|
)
|
|
def test_reverb_damping(input, expected):
|
|
np.testing.assert_allclose(
|
|
get_output("CALCULATE_DAMPING", input, "damping", "damping_int"),
|
|
expected,
|
|
**TOL_KWARGS,
|
|
)
|
|
|
|
@pytest.mark.parametrize(
|
|
"input", [-1, 0, 0.07, 0.23, 0.5, 0.64, 0.92, 1, 2]
|
|
)
|
|
def test_reverb_wet_dry_mix_conv(input):
|
|
c_vals = get_c("WET_DRY_MIX", input)
|
|
r = new_reverb()
|
|
r.set_wet_dry_mix(input)
|
|
p_vals = np.array([r.dry_int, r.wet_int], dtype=np.int32)
|
|
# -23 cause of the float to int conversion
|
|
np.testing.assert_allclose(c_vals, p_vals, rtol=2**-23, atol=0)
|
|
|
|
@pytest.mark.parametrize(
|
|
"input", [-1, 0, 0.07, 0.23, 0.5, 0.64, 0.92, 1, 2]
|
|
)
|
|
def test_reverb_st_wet_dry_mix_conv(input):
|
|
c_vals = get_c("WET_DRY_MIX_ST", input)
|
|
r = reverb_room_stereo(48000, 2)
|
|
r.set_wet_dry_mix(input)
|
|
p_vals = np.array([r.dry_int, r.wet_1_int, r.wet_2_int], dtype=np.int32)
|
|
# -23 cause of the float to int conversion
|
|
np.testing.assert_allclose(c_vals, p_vals, rtol=2**-23, atol=0)
|
|
|
|
@pytest.mark.parametrize(
|
|
"input", [-1, 100, 1000, 2000, 4000, 8000, 16000, 32000]
|
|
)
|
|
def test_reverb_cutoff(input):
|
|
c_vals = get_c("CUTOFF", input)
|
|
r = reverb_plate_stereo(48000, 2)
|
|
r.bandwidth = input
|
|
p_vals = r.lowpasses[0].coeff_b0_int
|
|
# -23 cause of the float to int conversion
|
|
np.testing.assert_allclose(c_vals, p_vals, rtol=2**-13, atol=0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
test_reverb_cutoff(8000) |