Files
SonicForgeStudio/tests/test_sub_tab_dsp.py

81 lines
2.8 KiB
Python

import os
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
import numpy as np
import pytest
from app.core.sub_tab_dsp import SubTabDSPEngine
def test_speed_ratio():
sr = 44100
y = np.sin(2 * np.pi * 440 * np.linspace(0, 1, sr, endpoint=False)).astype(np.float32)
# Pitch-preserving speed change
y_stretched = SubTabDSPEngine.change_speed(y, sr, 2.0, preserve_pitch=True)
assert abs(len(y_stretched) - sr // 2) < 2000 # Librosa might have frame alignment differences
# Simple resampling speed change
y_resampled = SubTabDSPEngine.change_speed(y, sr, 2.0, preserve_pitch=False)
assert len(y_resampled) == sr // 2
def test_normalize():
y = np.array([0.1, -0.5, 0.2, 0.4], dtype=np.float32)
y_norm = SubTabDSPEngine.normalize(y, target_db=0.0)
assert np.max(np.abs(y_norm)) == 1.0
def test_merge_back_to_parent():
sr = 1000
parent = np.ones(5000, dtype=np.float32)
edited = np.zeros(2000, dtype=np.float32)
# Merge at t=1.0s (index 1000), original duration 1.5s (1500 samples)
res = SubTabDSPEngine.merge_back_to_parent(
parent_track_audio=parent,
sr=sr,
edited_sub_audio=edited,
start_seconds=1.0,
original_duration_seconds=1.5
)
# Expected length: 5000 - 1500 + 2000 = 5500
assert len(res) == 5500
# Before 1.0s (1000 samples) should be mostly parent values (1.0)
assert np.allclose(res[:900], 1.0)
# Inside the edited range should be zero (except crossfades)
assert np.allclose(res[1100:2900], 0.0)
def test_apply_volume_automation_envelope():
sr = 44100
duration = 2.0
y = np.ones(int(sr * duration), dtype=np.float32) * 0.5 # Constant signal at -6dB
# Simple fade in from -inf to 0dB over 1 second
nodes = [
{"time": 0.0, "db": -60.0}, # Effectively -inf
{"time": 1.0, "db": 0.0},
{"time": 2.0, "db": 0.0},
]
y_automated = SubTabDSPEngine.apply_volume_automation_envelope(y, sr, nodes)
y_automated = SubTabDSPEngine.apply_volume_automation_envelope(y, sr, nodes)
# Check start: should be 0.5 * 10**(-30/20) due to clipping
expected_start_val = 0.5 * (10**(-30/20.0))
assert np.isclose(y_automated[0], expected_start_val, atol=1e-5)
# Check at 0.5 seconds: interpolated to -15dB (halfway between -30dB and 0dB)
# y * (10 ** (-15 / 20))
expected_mid_val = 0.5 * (10**(-15/20.0))
assert np.isclose(y_automated[int(0.5 * sr)], expected_mid_val, atol=1e-5)
# Check at 1.0 seconds: should be 0.5 * (10**(0/20)) = 0.5
assert np.isclose(y_automated[int(1.0 * sr)], 0.5, atol=1e-5)
# Check at end: should be 0.5
assert np.isclose(y_automated[-1], 0.5, atol=1e-5)
# Test with empty nodes
y_no_nodes = SubTabDSPEngine.apply_volume_automation_envelope(y, sr, [])
assert np.array_equal(y_no_nodes, y)