Files
UmbraAudio/tests/test_scene_break.py
2026-10-18 19:01:04 -07:00

69 lines
2.0 KiB
Python

# Copyright 2026 Umbra Tools (umbratools.com)
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
import numpy as np
import soundfile as sf
from umbraaudio.assembly import AudioStitcher
from umbraaudio.generation.scene_break import (
SCENE_BREAK_SILENCE_MS,
is_scene_break,
needs_silence,
write_scene_break_audio,
)
def test_is_scene_break_by_text() -> None:
assert is_scene_break("<<<>>>")
assert is_scene_break(" <<<>>> ")
def test_is_scene_break_by_type() -> None:
assert is_scene_break("", "scene_break")
assert not is_scene_break("Hello", "dialogue")
assert is_scene_break("<<<>>>", "narration")
def test_write_scene_break_audio(tmp_path) -> None:
out = tmp_path / "utt_0000.wav"
assert needs_silence(out)
write_scene_break_audio(out, sample_rate=24000)
assert out.exists()
data, sr = sf.read(str(out))
assert sr == 24000
expected = int(24000 * SCENE_BREAK_SILENCE_MS / 1000)
assert abs(len(data) - expected) < 5
assert np.allclose(data, 0.0)
assert not needs_silence(out)
def test_zero_byte_file_is_stale(tmp_path) -> None:
out = tmp_path / "utt_0000.wav"
out.write_bytes(b"")
assert needs_silence(out)
def test_stitch_includes_scene_break_silence(tmp_path) -> None:
tone = np.full(2400, 0.1, dtype=np.float32)
before = tmp_path / "utt_0000.wav"
scene = tmp_path / "utt_0001.wav"
after = tmp_path / "utt_0002.wav"
sf.write(str(before), tone, 24000)
sf.write(str(after), tone, 24000)
write_scene_break_audio(scene, sample_rate=24000)
output = tmp_path / "ch1_full.wav"
AudioStitcher().stitch_utterances([before, scene, after], output)
data, sr = sf.read(str(output))
assert sr == 24000
gap = int(24000 * 500 / 1000)
scene_samples = int(24000 * SCENE_BREAK_SILENCE_MS / 1000)
expected = 2400 + gap + scene_samples + gap + 2400
assert abs(len(data) - expected) < 10
assert np.allclose(data[2400 + gap : 2400 + gap + scene_samples], 0.0)