Spaces:
Sleeping
Sleeping
| """Tests for audio processor service.""" | |
| import pytest | |
| import numpy as np | |
| from backend.services.audio_processor import ( | |
| shift_and_stretch_single, | |
| process_all_stems, | |
| mix_stems, | |
| ) | |
| from backend.models.session import StemData | |
| def test_pitch_shift_up_2(sample_stems): | |
| """Pitch shifting up 2 semitones should not crash and should return audio.""" | |
| stems, sr = sample_stems | |
| for name, audio in stems.items(): | |
| result = shift_and_stretch_single( | |
| audio, sr, semitones=2, tempo_ratio=1.0, stem_type=name | |
| ) | |
| assert isinstance(result, np.ndarray) | |
| assert len(result) > 0 | |
| # Duration should be approximately the same (no time stretch) | |
| assert abs(len(result) - len(audio)) / sr < 0.1 # within 100ms | |
| def test_pitch_shift_down_4(sample_stems): | |
| """Pitch shifting down 4 semitones should work.""" | |
| stems, sr = sample_stems | |
| audio = stems["guitar"] | |
| result = shift_and_stretch_single( | |
| audio, sr, semitones=-4, tempo_ratio=1.0, stem_type="guitar" | |
| ) | |
| assert len(result) > 0 | |
| def test_time_stretch_faster(sample_stems): | |
| """Speeding up by 20% should produce shorter audio.""" | |
| stems, sr = sample_stems | |
| audio = stems["bass"] | |
| result = shift_and_stretch_single( | |
| audio, sr, semitones=0, tempo_ratio=1.2, stem_type="bass" | |
| ) | |
| expected_length = len(audio) / 1.2 | |
| assert abs(len(result) - expected_length) / sr < 0.2 # within 200ms | |
| def test_time_stretch_slower(sample_stems): | |
| """Slowing down by 20% should produce longer audio.""" | |
| stems, sr = sample_stems | |
| audio = stems["bass"] | |
| result = shift_and_stretch_single( | |
| audio, sr, semitones=0, tempo_ratio=0.8, stem_type="bass" | |
| ) | |
| expected_length = len(audio) / 0.8 | |
| assert abs(len(result) - expected_length) / sr < 0.2 | |
| def test_combined_shift_and_stretch(sample_stems): | |
| """Combined pitch+tempo should work in single pass.""" | |
| stems, sr = sample_stems | |
| audio = stems["guitar"] | |
| result = shift_and_stretch_single( | |
| audio, sr, semitones=3, tempo_ratio=1.15, stem_type="guitar" | |
| ) | |
| assert len(result) > 0 | |
| def test_no_change_passthrough(sample_stems): | |
| """Zero semitones + 1.0 ratio should return unchanged audio.""" | |
| stems, sr = sample_stems | |
| audio = stems["bass"] | |
| result = shift_and_stretch_single( | |
| audio, sr, semitones=0, tempo_ratio=1.0, stem_type="bass" | |
| ) | |
| np.testing.assert_array_almost_equal(result, audio, decimal=5) | |
| def test_process_all_stems_parallel(sample_stems): | |
| """Processing all stems in parallel should return all stems.""" | |
| stems_dict, sr = sample_stems | |
| stem_data = { | |
| name: StemData(name=name, audio=audio, sample_rate=sr) | |
| for name, audio in stems_dict.items() | |
| } | |
| results = process_all_stems(stem_data, semitones=2, tempo_ratio=1.1) | |
| assert set(results.keys()) == set(stems_dict.keys()) | |
| def test_mix_stems(sample_stems): | |
| """Mixing stems should produce audio without clipping.""" | |
| stems, sr = sample_stems | |
| mixed = mix_stems(stems, sr) | |
| assert np.max(np.abs(mixed)) <= 1.0 | |
| assert len(mixed) == max(len(a) for a in stems.values()) | |
| def test_mix_stems_empty(): | |
| """Mixing empty stems dict should return empty array.""" | |
| mixed = mix_stems({}, sample_rate=48000) | |
| assert len(mixed) == 0 | |
| def test_process_all_stems_no_change(sample_stems): | |
| """Processing with no changes should return copies.""" | |
| stems_dict, sr = sample_stems | |
| stem_data = { | |
| name: StemData(name=name, audio=audio, sample_rate=sr) | |
| for name, audio in stems_dict.items() | |
| } | |
| results = process_all_stems(stem_data, semitones=0, tempo_ratio=1.0) | |
| for name in stems_dict: | |
| np.testing.assert_array_almost_equal( | |
| results[name].audio, stem_data[name].audio, decimal=5 | |
| ) | |