File size: 3,821 Bytes
a0fcd39 184639f a0fcd39 184639f a0fcd39 | 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 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | """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
)
|