Files
gart/code/tests/test_emphasis.py

113 lines
4.6 KiB
Python

"""Tests for fcpxml/emphasis.py — the emphasis index (pure, no audio needed)."""
from fcpxml.emphasis import (
EmphasisWeights,
annotate_emphasis,
compute_emphasis,
pause_weight,
)
def test_zero_input_gives_zero_score():
assert compute_emphasis(0.0, 0.0, 0.0, 0.0, 0.0) == 0.0
def test_max_input_gives_max_score():
# pause sits inside the "dramatic beat" window, not a scene-change gap
score = compute_emphasis(
energy=1.0, pitch_delta=1.0, rate_delta=1.0, pause_before=1.5, word_duration=10.0
)
assert score == 1.0
def test_negative_pitch_delta_uses_magnitude():
a = compute_emphasis(0.0, pitch_delta=0.5, rate_delta=0.0, pause_before=0.0, word_duration=0.0)
b = compute_emphasis(0.0, pitch_delta=-0.5, rate_delta=0.0, pause_before=0.0, word_duration=0.0)
assert a == b > 0.0
def test_duration_saturates_beyond_cap():
at_cap = compute_emphasis(0.0, 0.0, 0.0, 0.0, word_duration=1.0, max_duration=1.0)
beyond = compute_emphasis(0.0, 0.0, 0.0, 0.0, word_duration=30.0, max_duration=1.0)
assert at_cap == beyond
class TestPauseWeight:
"""A long gap is a scene change, not emphasis — it must not outrank a
word the speaker actually hit hard. Grounded in real footage where 6-9s
gaps were topping the emphasis ranking."""
def test_dramatic_beat_counts_fully(self):
assert pause_weight(1.5, max_pause=1.5) == 1.0
def test_short_beat_counts_proportionally(self):
assert pause_weight(0.75, max_pause=1.5) == 0.5
def test_long_gap_is_ignored(self):
assert pause_weight(8.7, max_pause=1.5, ignore_above=3.0) == 0.0
def test_no_pause_is_zero(self):
assert pause_weight(0.0) == 0.0
def test_cutoff_can_be_disabled(self):
assert pause_weight(30.0, max_pause=1.5, ignore_above=0.0) == 1.0
def test_scene_change_scores_below_a_loud_word(self):
gap = compute_emphasis(0.25, 0.04, 0.0, pause_before=6.2, word_duration=0.5)
loud = compute_emphasis(1.00, 0.28, 0.0, pause_before=1.9, word_duration=0.2)
assert loud > gap
def test_higher_energy_weight_increases_energy_contribution():
low_weight = EmphasisWeights(energy=0.1, pitch_variation=0.0, rate_variation=0.0, pause_before=0.0, duration=0.0)
high_weight = EmphasisWeights(energy=1.0, pitch_variation=0.0, rate_variation=0.0, pause_before=0.0, duration=0.0)
# energy is the only nonzero factor for both weight sets, so normalized
# score should be identical regardless of the absolute weight value.
score_low = compute_emphasis(0.6, 0.0, 0.0, 0.0, 0.0, weights=low_weight)
score_high = compute_emphasis(0.6, 0.0, 0.0, 0.0, 0.0, weights=high_weight)
assert score_low == score_high
def test_all_zero_weights_returns_zero_not_error():
zero_weights = EmphasisWeights(0.0, 0.0, 0.0, 0.0, 0.0)
assert compute_emphasis(1.0, 1.0, 1.0, 1.0, 1.0, weights=zero_weights) == 0.0
def test_weights_round_trip_dict():
w = EmphasisWeights(energy=0.4, pitch_variation=0.3, rate_variation=0.1, pause_before=0.1, duration=0.1)
restored = EmphasisWeights.from_dict(w.as_dict())
assert restored == w
def test_from_dict_fills_missing_with_defaults():
restored = EmphasisWeights.from_dict({"energy": 0.9})
defaults = EmphasisWeights()
assert restored.energy == 0.9
assert restored.pitch_variation == defaults.pitch_variation
def test_annotate_emphasis_adds_score_per_word():
words = [
{"word": "hi", "start": 0.0, "end": 0.3, "energy": 0.2, "pitch_delta": 0.1, "rate_delta": 0.1, "pause_before": 0.0},
{"word": "WOW", "start": 1.0, "end": 1.5, "energy": 0.9, "pitch_delta": 0.8, "rate_delta": 0.7, "pause_before": 1.0},
]
annotated = annotate_emphasis(words)
assert len(annotated) == 2
assert all("emphasis" in w for w in annotated)
assert annotated[1]["emphasis"] > annotated[0]["emphasis"]
def test_annotate_emphasis_does_not_mutate_input():
words = [{"word": "hi", "start": 0.0, "end": 0.3, "energy": 0.5}]
annotate_emphasis(words)
assert "emphasis" not in words[0]
def test_annotate_emphasis_derives_duration_from_start_end():
"""A word with no explicit "duration" key gets it from end - start."""
base = {"energy": 0.0, "pitch_delta": 0.0, "rate_delta": 0.0, "pause_before": 0.0}
derived = annotate_emphasis([{"word": "hi", "start": 1.0, "end": 1.5, **base}], max_duration=0.5)
explicit = annotate_emphasis([{"word": "hi", "start": 0.0, "end": 0.0, "duration": 0.5, **base}], max_duration=0.5)
# duration is the only nonzero factor in both, so scores must match
assert derived[0]["emphasis"] == explicit[0]["emphasis"] > 0.0