"""Speech onsets: the lead-in of silence TTS puts before each sentence is measured and recorded.""" import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from pydub import AudioSegment from pydub.generators import Sine from core import magazine as mag def _clip(lead_ms: int, tone_ms: int = 400) -> AudioSegment: return AudioSegment.silent(lead_ms, frame_rate=24000) + Sine(300, sample_rate=24000).to_audio_segment(tone_ms).apply_gain(-6) def test_onset_is_the_leading_silence(): assert abs(mag._speech_onset_ms(_clip(700)) - 700) <= 20 assert mag._speech_onset_ms(_clip(0)) <= 10 def test_silent_or_tiny_clip_has_no_onset(): assert mag._speech_onset_ms(AudioSegment.silent(500, frame_rate=24000)) == 0 assert mag._speech_onset_ms(AudioSegment.silent(20, frame_rate=24000)) == 0 def test_onsets_are_written_per_segment(tmp_path): mp3 = tmp_path / "a.mp3" segs = [{"text": "One. Two."}, {"text": "Three."}] mag.write_audio_timings(mp3, segs, [0, 0, 1], [(0, 1000), (1000, 2000), (2000, 3000)], interview=False, onsets=[700, 650, 500]) rec = mag.read_audio_timings(mp3) assert [s["onsets"] for s in rec["segments"]] == [[700, 650], [500]] assert [s["times"] for s in rec["segments"]] == [[[0, 1000], [1000, 2000]], [[2000, 3000]]] def test_old_audio_onsets_are_measured_from_the_file(tmp_path): mp3 = tmp_path / "old.mp3" (_clip(600) + _clip(800)).export(mp3, format="mp3") total = int(AudioSegment.from_file(mp3).duration_seconds * 1000) timings = {"version": 1, "segments": [{"chars": 1, "times": [[0, 1000], [1000, total]]}]} got = mag.measure_speech_onsets(mp3, timings) assert got is not None and abs(got[0] - 600) <= 60 and abs(got[1] - 800) <= 60