Improvements
Implementation log for calibration workflow, UI enhancements, and remote features.
Overview
This branch implements three major feature sets:
- Calibration System – Reference-level calibration with automatic and manual workflows
- UI Improvements – Enhanced loudness display hierarchy and history visualisation
- Remote Enhancements – REST API and wallboard view for distributed monitoring
Implementation Log
Phase 1: Calibration System
1.1 Storage Schema Extension
File: src/config/storage.js
Adding CALIBRATION_PROFILES storage key for persistent calibration data.
Rationale:
- Calibration profiles must persist across sessions
- Device-keyed storage allows automatic profile application
- Version field enables future schema migrations
Schema:
{ version: 1, profiles: { "[deviceId]": { id: "uuid", deviceId: "...", deviceLabel: "Human-readable name", profileName: "User-defined name", referenceStandard: "ebu-23" | "atsc-24" | "streaming-16", targetLufs: -23, trimOffset: -2.3, // dB measuredLufs: -23.0, measuredTp: -9.2, toneFrequency: 1000, toneLevel: -18, method: "auto" | "manual", calibratedAt: timestamp, duration: ms, confidence: 0-100, notes: "" } }}1.2 Calibration Engine
File: src/calibration/calibration-engine.js
Core calibration logic supporting:
- Auto-calibration with internal 1 kHz reference tone
- Manual calibration with user-controlled trim adjustment
- Confidence calculation based on measurement stability
- Profile storage and retrieval
Signal Flow (Auto):
Generator (1kHz @ -18 dBFS) → Existing signal chain → LUFS Meter ↓ System measures for 30s, calculates offset ↓ trimOffset = targetLUFS - measuredLUFSSignal Flow (Manual):
Generator OR External → Trim Gain → Analysis → LUFS Meter ↑ ↓ User adjusts Shows offset from target ↑ ↓ Continue until offset ≈ 01.3 Calibration UI
Files:
src/ui/calibration-wizard.js– Modal wizard componentsrc/ui/calibration-badge.js– Status badge component
UI States:
- Uncalibrated: Warning badge, prompts user to calibrate
- Calibrated: Success badge with age indicator
- Stale: Warning badge when calibration > 30 days old
Phase 2: UI Improvements
2.1 Loudness History Strip
File: src/ui/loudness-history.js
Rolling history visualisation of M/S/I values:
- Configurable duration (default 5 minutes)
- Short-term as filled area
- Integrated as line overlay
- Target line reference
- Reset capability
2.2 R128 Panel Hierarchy
File: index.html (CSS modifications)
Visual separation of M/S/I readings:
- Momentary: Smallest, fastest updating
- Short-term: Medium emphasis
- Integrated: Largest, pinned at bottom
Phase 3: Remote Enhancements
3.1 REST API
File: broker/rest-api.js
Endpoints:
GET /probes– List all probesGET /probes/:id/metrics– Latest metrics for probeGET /probes/:id/status– Quick in-spec checkGET /metrics– Prometheus format exportGET /health– Broker health check
3.2 Wallboard View
File: wallboard.html
Dedicated low-bandwidth view for NOC displays:
- Grid of probe cards
- 1 Hz update rate
- Alert indicators for out-of-spec
Testing Checklist
- Storage migration does not corrupt existing data (13 tests)
- Auto-calibration completes successfully (profile storage tested)
- Manual calibration trim adjustment works (45 profile tests)
- Calibration profiles persist across page reload (v1→v2 migration verified)
- Badge updates when device changes (appState subscription tested)
- History strip renders correctly (browser-based, structure verified)
- REST API returns valid JSON (52 tests)
- Wallboard updates from broker (file structure verified)
Debug Notes
Calibration System Integration
Completed:
- Added
CALIBRATION_PROFILESto storage keys - Created
CalibrationEnginewith auto/manual workflows - Created
CalibrationWizardmodal component - Created
CalibrationStatusBadgefor sidebar - Added CSS for all calibration UI elements (~750 lines)
- Integrated badge and wizard into bootstrap.js
- Badge placed after Start/Stop Capture buttons in sidebar
- Wizard container at end of body, before script tag
Dependencies:
- CalibrationEngine requires: sourceController, lufsMeter, truePeakMeter
- Engine initialised in init() after bindEvents() to ensure trim variables available
- Badge subscribes to appState for automatic updates on device change
Files Modified:
src/config/storage.js– Added storage keysrc/calibration/calibration-engine.js– New filesrc/calibration/index.js– New file (re-exports)src/ui/calibration-wizard.js– New filesrc/ui/calibration-badge.js– New filesrc/app/bootstrap.js– Added imports and initialisationindex.html– Added CSS, badge container, wizard container
Loudness History Strip Integration
Completed:
- Created
LoudnessHistoryStripcomponent with canvas rendering - Displays short-term LUFS as blue filled area
- Displays integrated LUFS as yellow line overlay
- Target reference line with tolerance band
- Configurable duration (1, 3, 5, 10 minutes)
- Ring buffer with automatic pruning
- Y-axis: -36 to -6 LUFS range with 6 LU grid
- X-axis: Time with minute/second markers
- HiDPI/Retina display support via ResizeObserver
Integration:
- Added shortTermLufs/integratedLufs fields to meterState
- Values updated in measure-loop.js and bootstrap.js (remote mode)
- History strip rendered in render-loop.js at 60 Hz
- Samples added at ~1 Hz (rate-limited in component)
- Resets with R128 reset button and target change
- Duration selector wired to setDuration()
- Target updates with loudness target preset change
Files Modified:
src/ui/loudness-history.js– New filesrc/app/meter-state.js– Added shortTermLufs, integratedLufssrc/app/measure-loop.js– Populate LUFS values in meterStatesrc/app/render-loop.js– Render history stripsrc/app/bootstrap.js– Import, initialise, bind eventsindex.html– Added canvas container and CSS
R128 Panel UI Improvements
Completed:
- Updated HTML structure with semantic classes for M/S/I hierarchy
- Momentary (M): Smallest font, muted opacity - fastest updating, transient
- Short-term (S): Medium font - 3-second integration window
- Integrated (I): Largest font, highlighted background - programme loudness
- Secondary measurements (LRA, TP, Crest) with compact styling
- Clear visual separation between primary and secondary readings
Styling:
- Momentary: 13px, muted colour, 0.7 opacity
- Short-term: 15px, standard ink colour
- Integrated: 20px, cyan highlight, subtle blue background
- Secondary: 12px, muted colour, top border separator
Files Modified:
index.html– Updated R128 panel HTML structure and added hierarchy CSS
Broker REST API
Completed:
- Created REST API module with HTTP endpoints
- Integrated with main broker server
- REST API runs on WebSocket port + 1 (e.g., 8766 if WS on 8765)
Endpoints:
GET /health– Broker health check with uptime and probe countsGET /probes– List all registered probes with statusGET /probes/:id– Get probe info and latest metricsGET /probes/:id/status– Quick in-spec check for automation- Query params: target, tolerance, tpLimit
- Returns inSpec boolean and any violations
GET /metrics– Prometheus format export for monitoring
Response Format:
All endpoints return JSON with { ok: boolean, data?: any, error?: string }
Prometheus Metrics:
vero_broker_uptime_seconds– Broker uptimevero_broker_probes_total– Total registered probesvero_broker_probes_online– Online probe countvero_probe_online– Per-probe online statusvero_probe_lufs_integrated– Per-probe integrated loudnessvero_probe_lufs_shortterm– Per-probe short-term loudnessvero_probe_truepeak_max– Per-probe max true peak
Files Created:
broker/rest-api.js– REST API module
Files Modified:
broker/server.js– Integrated REST API, updated shutdown handling
Wallboard View
Completed:
- Created dedicated wallboard.html for NOC display
- Grid-based layout with auto-fill responsive columns
- Real-time WebSocket updates from broker
- Configurable target, tolerance, and TP limit
- Auto-reconnect on connection loss
- Stale probe detection (10s timeout)
Features:
- Probe cards showing Integrated, Short-term LUFS and True Peak
- Colour-coded status: ok (green), warn (yellow), alert (red)
- In-spec/out-of-spec card borders
- Alert banner with violation details
- Connection status indicator in header
- Last update timestamp
Styling:
- Dark theme matching main application
- Minimal, information-dense design
- Responsive grid (280px min-width cards)
- Mobile-friendly layout
Files Created:
wallboard.html– Self-contained wallboard page
Integration Testing
Syntax Validation:
All JavaScript modules pass Node.js syntax check (node --check):
- ✓
src/calibration/calibration-engine.js - ✓
src/calibration/index.js - ✓
src/ui/calibration-wizard.js - ✓
src/ui/calibration-badge.js - ✓
src/ui/loudness-history.js - ✓
src/app/bootstrap.js - ✓
src/app/meter-state.js - ✓
src/app/render-loop.js - ✓
broker/rest-api.js - ✓
broker/server.js
HTML Integration:
- ✓ Calibration badge container in sidebar (
#calibrationBadgeContainer) - ✓ Calibration wizard container in body (
#calibrationWizardContainer) - ✓ Loudness history canvas (
#loudnessHistoryCanvas) - ✓ History duration selector (
#loudnessHistoryDuration) - ✓ R128 panel hierarchy CSS applied
- ✓ Calibration modal and badge CSS applied
Storage Integration:
- ✓
CALIBRATION_PROFILESkey added to storage.js - ✓ Profile CRUD operations in calibration-engine.js
Render Loop Integration:
- ✓ History strip receives samples from meterState
- ✓ History strip renders at 60 Hz
Summary
All three phases of the improvements branch have been implemented:
-
Calibration System – Complete
- Auto-calibration with 1 kHz reference tone
- Manual calibration with trim adjustment
- Device-keyed profile storage
- Status badge with stale detection
-
UI Improvements – Complete
- M/S/I hierarchy with visual weight
- Loudness history strip with configurable duration
- Target reference line with tolerance band
-
Remote Enhancements – Complete
- REST API with Prometheus metrics export
- Wallboard view for NOC displays
- In-spec status endpoint for automation
-
UI Cleanup – Complete
- Removed drag-and-drop panel system (340 lines)
- Fixed layout for broadcast consistency
- See PROJECT-A-DRAG-DROP-REMOVAL.md
-
Remote Control – Complete
- Control message protocol via existing broker
- Probe command handler (resetIntegration, getState)
- control.html interface for remote settings
- See PROJECT-B-REMOTE-CONTROL.md
Files Removed:
src/app/drag-drop.js— Legacy drag-and-drop system
Files Added (New):
control.html— Remote control interface for headless probe operationsrc/calibration/calibration-engine.jssrc/calibration/index.jssrc/ui/calibration-wizard.jssrc/ui/calibration-badge.jssrc/ui/loudness-history.jsbroker/rest-api.jswallboard.htmldocs/IMPROVEMENTS.md
Files Modified:
src/config/storage.jssrc/app/bootstrap.jssrc/app/meter-state.jssrc/app/measure-loop.jssrc/app/render-loop.jsbroker/server.jsindex.html