Files
ethanfel-ComfyUI-SAM-Audio/tests/test_audio.py
T

104 lines
3.0 KiB
Python

import pytest
import torch
from sam_audio_comfy.audio import (
AudioChunk,
crossfade_audio_chunks,
plan_audio_chunks,
prepare_audio,
prepare_visual_prompt,
result_to_audio,
slice_visual_frames,
)
def test_chunk_plan_covers_audio_with_requested_overlap():
assert plan_audio_chunks(21, 1, 10.0, 2.0) == [
AudioChunk(0, 10),
AudioChunk(8, 18),
AudioChunk(16, 21),
]
assert plan_audio_chunks(21, 1, 0.0, 2.0) == [AudioChunk(0, 21)]
assert plan_audio_chunks(5, 1, 10.0, 2.0) == [AudioChunk(0, 5)]
with pytest.raises(ValueError, match="shorter than chunk_duration"):
plan_audio_chunks(21, 1, 10.0, 10.0)
def test_crossfade_audio_chunks_normalizes_overlap():
first = torch.ones(1, 1, 6)
second = torch.full((1, 1, 6), 3.0)
output = crossfade_audio_chunks(
[(AudioChunk(0, 6), first), (AudioChunk(4, 10), second)], 10
)
assert torch.equal(output[..., :4], torch.ones(1, 1, 4))
assert torch.allclose(output[0, 0, 4:6], torch.tensor([5 / 3, 7 / 3]))
assert torch.equal(output[..., 6:], torch.full((1, 1, 4), 3.0))
def test_visual_frames_are_sliced_to_chunk_time_range():
frames = torch.arange(10).view(10, 1)
assert torch.equal(
slice_visual_frames(frames, AudioChunk(2, 6), 10), frames[2:6]
)
assert torch.equal(
slice_visual_frames(frames, AudioChunk(0, 10), 10), frames
)
def test_prepare_audio_preserves_batch_and_resamples():
waveform = torch.stack(
[torch.ones(2, 8), torch.full((2, 8), 0.5)], dim=0
)
rows, length = prepare_audio(
{"waveform": waveform, "sample_rate": 8}, target_sample_rate=4
)
assert len(rows) == 2
assert rows[0].shape == (2, 4)
assert rows[1].shape == (2, 4)
assert length == 4
def test_result_to_audio_crops_and_pads_mono_batch():
audio = result_to_audio(
[torch.arange(8), torch.arange(3)], sample_rate=48_000, target_length=5
)
assert audio["sample_rate"] == 48_000
assert audio["waveform"].shape == (2, 1, 5)
assert torch.equal(audio["waveform"][0, 0], torch.arange(5).float())
assert torch.equal(
audio["waveform"][1, 0], torch.tensor([0.0, 1.0, 2.0, 0.0, 0.0])
)
def test_prepare_visual_prompt_converts_layout_scale_and_repeats_mask():
images = torch.zeros(3, 4, 6, 3)
images[..., 0] = 1.0
mask = torch.tensor([[0.0, 1.0], [0.0, 0.0]])
frames, masks = prepare_visual_prompt(images, mask)
assert frames.shape == (3, 3, 4, 6)
assert frames.dtype == torch.uint8
assert frames[:, 0].min().item() == 255
assert frames[:, 1:].max().item() == 0
assert masks.shape == (3, 1, 4, 6)
assert masks.dtype == torch.bool
assert torch.equal(masks[0], masks[1])
def test_prepare_visual_prompt_rejects_mismatched_frame_counts():
images = torch.zeros(3, 4, 6, 3)
mask = torch.zeros(2, 4, 6)
try:
prepare_visual_prompt(images, mask)
except ValueError as error:
assert "2 frames" in str(error)
else:
raise AssertionError("expected a frame-count validation error")