Level 3: small fixes and report
This commit is contained in:
@@ -21,7 +21,7 @@ import soundfile as sf
|
||||
|
||||
from core.aac_coder import aac_coder_1, aac_coder_2, aac_coder_3, aac_read_wav_stereo_48k
|
||||
from core.aac_decoder import aac_decoder_1, aac_decoder_2, aac_decoder_3, aac_remove_padding
|
||||
from core.aac_utils import snr_db
|
||||
from core.aac_utils import snr_db, estimate_lag_mono, match_gain
|
||||
from core.aac_types import *
|
||||
|
||||
|
||||
@@ -151,6 +151,29 @@ def test_aac_coder_seq_schema_and_shapes(mk_random_stereo_wav: Path) -> None:
|
||||
assert chl_f.shape == (1024, 1)
|
||||
assert chr_f.shape == (1024, 1)
|
||||
|
||||
@pytest.mark.parametrize("mk_actual_stereo_wav", [0.5], indirect=True)
|
||||
def test_level_1_gain_close_to_one(
|
||||
mk_actual_stereo_wav: Path,
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""
|
||||
Guardrail: decoded signal should not have a large global gain mismatch.
|
||||
"""
|
||||
x_ref, fs = aac_read_wav_stereo_48k(mk_actual_stereo_wav)
|
||||
assert int(fs) == 48000
|
||||
|
||||
out_wav = tmp_path / "decoded_level3.wav"
|
||||
aac_seq_1: AACSeq1 = aac_coder_1(mk_actual_stereo_wav)
|
||||
y_hat: StereoSignal = aac_decoder_1(aac_seq_1, out_wav)
|
||||
|
||||
n = min(x_ref.shape[0], y_hat.shape[0])
|
||||
x_ref = x_ref[:n, :]
|
||||
y_hat = y_hat[:n, :]
|
||||
|
||||
g = match_gain(x_ref, y_hat)
|
||||
# print (f"g = {g}")
|
||||
# Allow some slack but catch big scaling regressions
|
||||
assert 0.75 <= g <= 1.25
|
||||
|
||||
@pytest.mark.parametrize("mk_random_stereo_wav", [0.5], indirect=True)
|
||||
def test_end_to_end_aac_coder_decoder_high_snr(mk_random_stereo_wav: Path, tmp_path: Path) -> None:
|
||||
@@ -207,6 +230,30 @@ def test_aac_coder_2_seq_schema_and_shapes(mk_random_stereo_wav: Path) -> None:
|
||||
assert coeffs.shape == (4, 1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mk_actual_stereo_wav", [0.5], indirect=True)
|
||||
def test_level_2_gain_close_to_one(
|
||||
mk_actual_stereo_wav: Path,
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""
|
||||
Guardrail: decoded signal should not have a large global gain mismatch.
|
||||
"""
|
||||
x_ref, fs = aac_read_wav_stereo_48k(mk_actual_stereo_wav)
|
||||
assert int(fs) == 48000
|
||||
|
||||
out_wav = tmp_path / "decoded_level3.wav"
|
||||
aac_seq_2: AACSeq2 = aac_coder_2(mk_actual_stereo_wav)
|
||||
y_hat: StereoSignal = aac_decoder_2(aac_seq_2, out_wav)
|
||||
|
||||
n = min(x_ref.shape[0], y_hat.shape[0])
|
||||
x_ref = x_ref[:n, :]
|
||||
y_hat = y_hat[:n, :]
|
||||
|
||||
g = match_gain(x_ref, y_hat)
|
||||
# print (f"g = {g}")
|
||||
# Allow some slack but catch big scaling regressions
|
||||
assert 0.75 <= g <= 1.25
|
||||
|
||||
@pytest.mark.parametrize("mk_random_stereo_wav", [0.5], indirect=True)
|
||||
def test_end_to_end_level_2_high_snr(mk_random_stereo_wav: Path, tmp_path: Path) -> None:
|
||||
x_ref, fs = sf.read(str(mk_random_stereo_wav), always_2d=True)
|
||||
@@ -294,6 +341,90 @@ def test_aac_coder_3_seq_schema_and_shapes(mk_actual_stereo_wav: Path) -> None:
|
||||
else:
|
||||
assert np.isscalar(G)
|
||||
|
||||
@pytest.mark.parametrize("mk_actual_stereo_wav", [0.5], indirect=True)
|
||||
def test_level_3_estimated_lag(
|
||||
mk_actual_stereo_wav: Path,
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""
|
||||
Check that the estimated lag between reference and decoded
|
||||
signal is small (zero), to prevent catastrophic misalignment.
|
||||
"""
|
||||
x_ref, fs = aac_read_wav_stereo_48k(mk_actual_stereo_wav)
|
||||
assert int(fs) == 48000
|
||||
|
||||
out_wav = tmp_path / "decoded_level3.wav"
|
||||
|
||||
aac_seq_3: AACSeq3 = aac_coder_3(mk_actual_stereo_wav)
|
||||
y_hat: StereoSignal = aac_decoder_3(aac_seq_3, out_wav)
|
||||
|
||||
# Use only common length
|
||||
n = min(x_ref.shape[0], y_hat.shape[0])
|
||||
x_ref = x_ref[:n, :]
|
||||
y_hat = y_hat[:n, :]
|
||||
|
||||
lag_L = estimate_lag_mono(x_ref[:, 0], y_hat[:, 0], max_lag=4096)
|
||||
lag_R = estimate_lag_mono(x_ref[:, 1], y_hat[:, 1], max_lag=4096)
|
||||
|
||||
# We allow zero latency
|
||||
assert abs(lag_L) == 0
|
||||
assert abs(lag_R) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mk_actual_stereo_wav", [0.5], indirect=True)
|
||||
def test_level_3_not_lr_swapped(
|
||||
mk_actual_stereo_wav: Path,
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""
|
||||
Ensure the decoded stereo channels are not swapped.
|
||||
If channels are swapped, SNR against the original drops a lot,
|
||||
while SNR against swapped reference increases.
|
||||
"""
|
||||
x_ref, fs = aac_read_wav_stereo_48k(mk_actual_stereo_wav)
|
||||
assert int(fs) == 48000
|
||||
|
||||
out_wav = tmp_path / "decoded_level3.wav"
|
||||
|
||||
aac_seq_3: AACSeq3 = aac_coder_3(mk_actual_stereo_wav)
|
||||
y_hat: StereoSignal = aac_decoder_3(aac_seq_3, out_wav)
|
||||
|
||||
n = min(x_ref.shape[0], y_hat.shape[0])
|
||||
x_ref = x_ref[:n, :]
|
||||
y_hat = y_hat[:n, :]
|
||||
|
||||
snr_normal = snr_db(x_ref, y_hat)
|
||||
snr_swapped = snr_db(x_ref[:, [1, 0]], y_hat)
|
||||
|
||||
# If the decoded output were swapped, snr_swapped would be significantly higher.
|
||||
assert snr_normal >= snr_swapped
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mk_actual_stereo_wav", [0.5], indirect=True)
|
||||
def test_level_3_gain_close_to_one(
|
||||
mk_actual_stereo_wav: Path,
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""
|
||||
Guardrail: decoded signal should not have a large global gain mismatch.
|
||||
"""
|
||||
x_ref, fs = aac_read_wav_stereo_48k(mk_actual_stereo_wav)
|
||||
assert int(fs) == 48000
|
||||
|
||||
out_wav = tmp_path / "decoded_level3.wav"
|
||||
aac_seq_3: AACSeq3 = aac_coder_3(mk_actual_stereo_wav)
|
||||
y_hat: StereoSignal = aac_decoder_3(aac_seq_3, out_wav)
|
||||
|
||||
n = min(x_ref.shape[0], y_hat.shape[0])
|
||||
x_ref = x_ref[:n, :]
|
||||
y_hat = y_hat[:n, :]
|
||||
|
||||
g = match_gain(x_ref, y_hat)
|
||||
|
||||
# Allow some slack but catch big scaling regressions
|
||||
assert 0.75 <= g <= 1.25
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mk_actual_stereo_wav", [0.5], indirect=True)
|
||||
def test_end_to_end_level_3_high_snr(mk_actual_stereo_wav: Path, tmp_path: Path) -> None:
|
||||
@@ -310,5 +441,4 @@ def test_end_to_end_level_3_high_snr(mk_actual_stereo_wav: Path, tmp_path: Path)
|
||||
|
||||
n = min(x_ref.shape[0], y_hat.shape[0])
|
||||
s = snr_db(x_ref[:n, :], y_hat[:n, :])
|
||||
# print(f" with SNR={s}")
|
||||
assert s > 7.0
|
||||
assert s > 8.0
|
||||
|
||||
Reference in New Issue
Block a user