Upload
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
"""Streaming-TTS chunk reassembly and the near-miss log. Both are pure —
|
||||
no network, no audio device, no ONNX model."""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||
|
||||
from bolt_pet.audio.tts import chunks_to_int16
|
||||
from bolt_pet.audio.wake_word import NearMissLog
|
||||
|
||||
|
||||
def _pcm(*values):
|
||||
return np.array(values, dtype=np.int16).tobytes()
|
||||
|
||||
|
||||
def test_whole_samples_pass_straight_through():
|
||||
chunks = list(chunks_to_int16([_pcm(1, 2), _pcm(3, 4)]))
|
||||
assert np.concatenate(chunks).tolist() == [1, 2, 3, 4]
|
||||
|
||||
|
||||
def test_a_sample_split_across_two_http_chunks_is_rejoined():
|
||||
# The killer bug this exists to prevent: an odd byte at a chunk boundary
|
||||
# shifts everything after it by one byte and plays as static.
|
||||
raw = _pcm(100, -200, 300, -400)
|
||||
chunks = list(chunks_to_int16([raw[:3], raw[3:]]))
|
||||
assert np.concatenate(chunks).tolist() == [100, -200, 300, -400]
|
||||
|
||||
|
||||
def test_many_odd_boundaries_in_a_row():
|
||||
raw = _pcm(*range(1, 21))
|
||||
pieces = [raw[i:i + 3] for i in range(0, len(raw), 3)] # every boundary odd
|
||||
assert np.concatenate(list(chunks_to_int16(pieces))).tolist() == list(range(1, 21))
|
||||
|
||||
|
||||
def test_empty_chunks_are_skipped():
|
||||
assert list(chunks_to_int16([b"", b""])) == []
|
||||
|
||||
|
||||
def test_a_dangling_byte_at_the_end_is_dropped_not_played():
|
||||
raw = _pcm(7, 8) + b"\x01"
|
||||
assert np.concatenate(list(chunks_to_int16([raw]))).tolist() == [7, 8]
|
||||
|
||||
|
||||
# ── wake-word near misses ───────────────────────────────────────────────────
|
||||
|
||||
def test_scores_just_under_the_threshold_are_recorded():
|
||||
log = NearMissLog(limit=10, margin=0.2)
|
||||
assert log.observe(0.45, threshold=0.5, timestamp=1.0) is True
|
||||
assert log.entries() == [(1.0, 0.45, 0.5)]
|
||||
|
||||
|
||||
def test_detections_and_background_noise_are_not_near_misses():
|
||||
log = NearMissLog(limit=10, margin=0.2)
|
||||
assert log.observe(0.90, threshold=0.5, timestamp=1.0) is False # it fired
|
||||
assert log.observe(0.05, threshold=0.5, timestamp=2.0) is False # just noise
|
||||
assert log.entries() == []
|
||||
|
||||
|
||||
def test_peak_tracks_every_score_not_just_near_misses():
|
||||
log = NearMissLog(limit=10, margin=0.2)
|
||||
log.observe(0.30, threshold=0.5, timestamp=1.0)
|
||||
log.observe(0.95, threshold=0.5, timestamp=2.0)
|
||||
log.observe(0.10, threshold=0.5, timestamp=3.0)
|
||||
assert log.peak == 0.95
|
||||
|
||||
|
||||
def test_the_log_is_bounded():
|
||||
log = NearMissLog(limit=3, margin=0.2)
|
||||
for i in range(10):
|
||||
log.observe(0.45, threshold=0.5, timestamp=float(i))
|
||||
assert len(log.entries()) == 3
|
||||
assert log.entries()[-1][0] == 9.0
|
||||
|
||||
|
||||
def test_clear_resets_peak_and_entries():
|
||||
log = NearMissLog(limit=3, margin=0.2)
|
||||
log.observe(0.45, threshold=0.5, timestamp=1.0)
|
||||
log.clear()
|
||||
assert log.entries() == [] and log.peak == 0.0
|
||||
Reference in New Issue
Block a user