forked from ChelseaKR/olive-bark-logger
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_calibrate.py
More file actions
110 lines (85 loc) · 3.66 KB
/
Copy pathtest_calibrate.py
File metadata and controls
110 lines (85 loc) · 3.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
"""Calibration math, the level meter, and the calibrate CLI."""
from __future__ import annotations
from monitor.calibrate import (
compute_offset,
main_calibrate,
measure_levels,
meter_bar,
suggest_threshold,
)
from monitor.capture import LoudRegion, synthetic_session
from monitor.level import SILENCE_FLOOR_DBFS
from store import EventStore
def test_compute_offset():
assert compute_offset(measured_dbfs=-50.0, reference_spl_db=60.0) == 110.0
def test_suggest_threshold_uses_median_plus_margin():
assert suggest_threshold([-40, -40, -40], margin_db=6.0) == -34.0
def test_suggest_threshold_empty():
assert suggest_threshold([], margin_db=6.0) == SILENCE_FLOOR_DBFS + 6.0
def test_meter_bar_clamps():
assert meter_bar(10.0, width=10).startswith("[##########]") # above ceil -> full
assert meter_bar(-200.0, width=10).startswith("[----------]") # below floor -> empty
def test_meter_bar_midscale():
bar = meter_bar(-30.0, floor=-60.0, ceil=0.0, width=10)
assert bar.startswith("[#####-----]")
def test_measure_levels_respects_cap():
source = synthetic_session(10.0, [LoudRegion(0.0, 10.0, 0.3)], frame_size=1600)
levels = measure_levels(source, max_frames=5)
assert len(levels) == 5
assert all(lvl > -20 for lvl in levels) # loud tone is well above silence
def test_main_calibrate_stores_offset(tmp_path, capsys):
db = tmp_path / "olive.db"
cfg = tmp_path / "cfg.json"
cfg.write_text(f'{{"db_path": "{db}"}}')
def factory(config):
return synthetic_session(3.0, [LoudRegion(0.0, 3.0, 0.3)], frame_size=config.frame_size)
rc = main_calibrate(
["--config", str(cfg), "--reference-db", "70", "--seconds", "2"], source_factory=factory
)
assert rc == 0
assert "offset" in capsys.readouterr().out
with EventStore(db) as store:
calib = store.get_calibration()
assert calib is not None
offset, note = calib
# measured ~ -10.5 dBFS for amplitude 0.3, so offset ~ 70 - (-10.5) = ~80.5
assert 75.0 < offset < 86.0
assert "70.0 dB" in note
# Provenance not supplied -> recorded as not recorded.
assert "Reference instrument not recorded" in note
def test_main_calibrate_appends_and_records_reference_instrument(tmp_path, capsys):
# R2: the reference-instrument provenance is stored both structurally (column on
# the append-only history) and in the human-readable calibration note.
db = tmp_path / "olive.db"
cfg = tmp_path / "cfg.json"
cfg.write_text(f'{{"db_path": "{db}"}}')
def factory(config):
return synthetic_session(3.0, [LoudRegion(0.0, 3.0, 0.3)], frame_size=config.frame_size)
# Seed an existing epoch so we can prove calibrate appends (never updates).
with EventStore(db) as store:
store.add_calibration(1.0, "old", effective_from=0.0)
rc = main_calibrate(
[
"--config",
str(cfg),
"--reference-db",
"70",
"--seconds",
"2",
"--reference-instrument",
"Brand X, IEC 61672 Class 2",
],
source_factory=factory,
)
assert rc == 0
capsys.readouterr()
with EventStore(db) as store:
history = store.calibration_history()
calib = store.get_calibration()
assert len(history) == 2 # appended, not overwritten
latest = history[-1]
assert latest.reference_instrument == "Brand X, IEC 61672 Class 2"
assert "Reference instrument: Brand X, IEC 61672 Class 2." in (latest.note or "")
# Backward-compatible accessor surfaces the same provenance-bearing note.
assert calib is not None
assert "Reference instrument: Brand X, IEC 61672 Class 2." in calib[1]