chore: initial commit
This commit is contained in:
66
choir-mixer/tests/test_mixer.py
Normal file
66
choir-mixer/tests/test_mixer.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import numpy as np
|
||||
from mixer import normalize_rms, mix_streams, soft_limit
|
||||
|
||||
TARGET_DBFS = -20
|
||||
|
||||
|
||||
class TestNormalizeRms:
|
||||
def test_silence_stays_silent(self, silence):
|
||||
result = normalize_rms(silence, TARGET_DBFS)
|
||||
assert np.allclose(result, 0.0)
|
||||
|
||||
def test_quiet_tone_gets_louder(self, quiet_tone):
|
||||
original_rms = np.sqrt(np.mean(quiet_tone ** 2))
|
||||
result = normalize_rms(quiet_tone, TARGET_DBFS)
|
||||
result_rms = np.sqrt(np.mean(result ** 2))
|
||||
assert result_rms > original_rms
|
||||
|
||||
def test_loud_tone_gets_quieter(self, loud_tone):
|
||||
original_rms = np.sqrt(np.mean(loud_tone ** 2))
|
||||
result = normalize_rms(loud_tone, TARGET_DBFS)
|
||||
result_rms = np.sqrt(np.mean(result ** 2))
|
||||
assert result_rms < original_rms
|
||||
|
||||
def test_normalized_to_target(self, loud_tone):
|
||||
result = normalize_rms(loud_tone, TARGET_DBFS)
|
||||
result_rms = np.sqrt(np.mean(result ** 2))
|
||||
result_dbfs = 20 * np.log10(result_rms + 1e-10)
|
||||
assert abs(result_dbfs - TARGET_DBFS) < 1.0 # within 1 dB
|
||||
|
||||
|
||||
class TestMixStreams:
|
||||
def test_single_stream_unchanged(self, loud_tone):
|
||||
result = mix_streams([loud_tone])
|
||||
assert np.allclose(result, loud_tone)
|
||||
|
||||
def test_two_streams_summed(self, loud_tone):
|
||||
result = mix_streams([loud_tone, loud_tone])
|
||||
# Two identical streams summed should be louder
|
||||
assert np.max(np.abs(result)) > np.max(np.abs(loud_tone))
|
||||
|
||||
def test_empty_list_returns_silence(self, silence):
|
||||
result = mix_streams([])
|
||||
assert result.shape[0] == 960
|
||||
assert np.allclose(result, 0.0)
|
||||
|
||||
def test_different_lengths_uses_shortest(self):
|
||||
short = np.ones(480, dtype=np.float32) * 0.5
|
||||
long = np.ones(960, dtype=np.float32) * 0.5
|
||||
result = mix_streams([short, long])
|
||||
assert result.shape[0] == 480
|
||||
|
||||
|
||||
class TestSoftLimit:
|
||||
def test_quiet_signal_unchanged(self, quiet_tone):
|
||||
result = soft_limit(quiet_tone)
|
||||
assert np.allclose(result, quiet_tone, atol=0.001)
|
||||
|
||||
def test_clipping_signal_contained(self, clipping_tone):
|
||||
result = soft_limit(clipping_tone)
|
||||
assert np.max(np.abs(result)) <= 1.0
|
||||
|
||||
def test_preserves_sign(self, clipping_tone):
|
||||
result = soft_limit(clipping_tone)
|
||||
# Signs should match where input is non-zero
|
||||
nonzero = np.abs(clipping_tone) > 0.01
|
||||
assert np.all(np.sign(result[nonzero]) == np.sign(clipping_tone[nonzero]))
|
||||
Reference in New Issue
Block a user