Correct audio metering and realtime displays

This commit is contained in:
Mikei386
2026-07-22 10:50:15 +02:00
parent 97352ecfce
commit 2e868bfa3a
26 changed files with 999 additions and 903 deletions
+28 -20
View File
@@ -106,7 +106,7 @@ const CONFIG = {
VU_REF_IS_PLUS4: true,
// 0 VU soll +4 dBu entsprechen → DIGITAL_REF + 4 dB.
VU_DBFS_REF: -14.0,
VU_OFFSET_DB: 1.92,
VU_OFFSET_DB: 0.0,
VU_HEADER_SHOW_VALUE: false,
TP_OFFSET_DB: 0.0,
TP_HEADER_SHOW_VALUE: false,
@@ -119,8 +119,9 @@ const CONFIG = {
PPM_RED_BAR_ONLY: true,
TP_RED_BAR_ONLY: true,
RMS_RED_BAR_ONLY: true,
RMS_TC_MODE: 'fast', // 'impulse' (35 ms), 'fast' (125 ms), 'slow' (1000 ms), 'none'
RMS_TC_MS: null, // optional override in ms (falls gesetzt, überschreibt den Modus)
// True-RMS integration is performed sample-continuously on linear power in
// the backend. "window" is a rectangular sliding 300-ms measurement.
RMS_TC_MODE: 'fast', // 'fast', 'slow', 'window'
VU_COLOR_NORMAL: '#ffe066',
VU_COLOR_WARN: '#ff3b3b',
PPM_DIN_COLOR_NORMAL: '#ffe066',
@@ -161,9 +162,6 @@ const CONFIG = {
PPM_DIN_RED_START: 0,
// Fixed RTW/DIN profile: 10 ms integration and 20 dB return in 1.5 s.
PPM_DIN_ATTACK_MS: 10,
// Non-normative: when enabled, PPM DIN attack becomes instant (no integration).
// Useful to compensate perceived meter lag caused by device / pipeline latency.
PPM_DIN_FAST_ATTACK: false,
PPM_DIN_DECAY_DB_PER_S: 20 / 1.5,
// Hold time for DIN PPM: verlängert auf 1000 ms (1 s), damit der PeakHold
// auch bei kurzen Transienten deutlich sichtbar bleibt. Gemäß
@@ -589,9 +587,9 @@ const PHOENIX_GLOBAL_OPTION_KEYS = Object.freeze([
'LR_FRACTIONAL_DELAY_SAMPLES',
'PPM_DIN_ATTACK_MS',
'PPM_DIN_DECAY_DB_PER_S',
'PPM_DIN_FAST_ATTACK',
'PPM_EBU_ATTACK_MS',
'PPM_EBU_DECAY_DB_PER_S',
'RMS_TC_MODE',
'LUFS_I_WINDOW_MIN',
'LUFS_I_NORM_ENABLED',
'PPM_DIN_LOUDNESS_BOXES',
@@ -679,8 +677,8 @@ const BROADCAST_STANDARDS = {
};
const STORAGE_KEY = 'analyzer_config';
const VU_OFFSET_ALIGNMENT_DB = 1.92;
const VU_OFFSET_ALIGNMENT_MIGRATION_KEY = 'migrate_vu_offset_alignment_plus2_v1';
const VU_OFFSET_DEFAULT_DB = 0.0;
const VU_OFFSET_ZERO_MIGRATION_KEY = 'migrate_vu_offset_default_zero_v2';
const INPUT_OFFSET_DB_MIN = -60;
const INPUT_OFFSET_DB_MAX = 20;
const LR_DELAY_ZERO_MIGRATION_KEY = 'migrate_lr_delay_zero_to_0_05_v1';
@@ -845,21 +843,23 @@ function loadConfig(opts = {}) {
if (!Number.isFinite(CONFIG.PPM_DIN_LOUDNESS_OFFSET_DB)) CONFIG.PPM_DIN_LOUDNESS_OFFSET_DB = 0;
CONFIG.PPM_DIN_LOUDNESS_OFFSET_DB = Math.max(-7, Math.min(7, CONFIG.PPM_DIN_LOUDNESS_OFFSET_DB));
try {
const needsVuMigration = !localStorage.getItem(VU_OFFSET_ALIGNMENT_MIGRATION_KEY);
const needsVuMigration = !localStorage.getItem(VU_OFFSET_ZERO_MIGRATION_KEY);
const savedVuOffset = Number(saved?.VU_OFFSET_DB);
const oldDefaultOffset = Number(CONFIG_DEFAULTS?.VU_OFFSET_DB);
const looksLikeOldDefault = !Number.isFinite(savedVuOffset)
|| Math.abs(savedVuOffset - oldDefaultOffset) < 0.02
const looksLikeOldAutomaticOffset = !Number.isFinite(savedVuOffset)
|| Math.abs(savedVuOffset - 1.92) < 0.02
|| Math.abs(savedVuOffset - (-0.08)) < 0.02
|| Math.abs(savedVuOffset - (-0.05)) < 0.02;
if (needsVuMigration && looksLikeOldDefault) {
CONFIG.VU_OFFSET_DB = VU_OFFSET_ALIGNMENT_DB;
if (needsVuMigration && looksLikeOldAutomaticOffset) {
CONFIG.VU_OFFSET_DB = VU_OFFSET_DEFAULT_DB;
}
if (needsVuMigration) localStorage.setItem(VU_OFFSET_ALIGNMENT_MIGRATION_KEY, '1');
if (needsVuMigration) localStorage.setItem(VU_OFFSET_ZERO_MIGRATION_KEY, '1');
} catch (_) {}
if (!Number.isFinite(CONFIG.LUFS_I_WINDOW_MIN)) CONFIG.LUFS_I_WINDOW_MIN = CONFIG_DEFAULTS.LUFS_I_WINDOW_MIN ?? 4;
CONFIG.LUFS_I_WINDOW_MIN = Math.max(1, Math.min(10, Math.round(CONFIG.LUFS_I_WINDOW_MIN)));
CONFIG.RMS_TC_MODE = (CONFIG.RMS_TC_MODE === 'slow' || CONFIG.RMS_TC_MODE === 'window')
? CONFIG.RMS_TC_MODE
: 'fast';
CONFIG.LUFS_I_NORM_ENABLED = !!CONFIG.LUFS_I_NORM_ENABLED;
CONFIG.STOPWATCH_DISPLAY_STYLE = (CONFIG.STOPWATCH_DISPLAY_STYLE === 'seven') ? 'seven' : 'mono';
@@ -876,7 +876,6 @@ function loadConfig(opts = {}) {
if (!Number.isFinite(CONFIG.LR_FRACTIONAL_DELAY_SAMPLES)) CONFIG.LR_FRACTIONAL_DELAY_SAMPLES = CONFIG_DEFAULTS.LR_FRACTIONAL_DELAY_SAMPLES;
CONFIG.LR_FRACTIONAL_DELAY_SAMPLES = Math.max(-1.5, Math.min(1.5, Number(CONFIG.LR_FRACTIONAL_DELAY_SAMPLES)));
CONFIG.PHOENIX_BASE_URL = normalizePhoenixBaseUrlForCurrentClient(CONFIG.PHOENIX_BASE_URL || CONFIG_DEFAULTS.PHOENIX_BASE_URL || DEFAULT_PHOENIX_BASE_URL);
CONFIG.PPM_DIN_FAST_ATTACK = !!CONFIG.PPM_DIN_FAST_ATTACK;
// Migrate stale profiles: detector ballistics are standards profiles,
// not user-adjustable display preferences.
CONFIG.PPM_DIN_ATTACK_MS = 10;
@@ -1055,6 +1054,12 @@ function buildPhoenixGlobalConfigPayload() {
return (mode === '1_3' || mode === '1_6' || mode === '1_12') ? mode : '1_6';
};
const phaseAmplitudeMode = normalizePhaseAmplitudeMode(CONFIG.PHASE_AMPLITUDE_MODE);
const rmsIntegration = (() => {
const mode = String(CONFIG.RMS_TC_MODE || '').trim().toLowerCase();
if (mode === 'slow' || mode === 'window') return mode;
if (mode === 'none' || mode === 'window300') return 'window';
return 'fast';
})();
return {
fftSize,
rtaBpoMode: normalizeRtaBpoMode(CONFIG.RTA_BPO_MODE),
@@ -1065,9 +1070,9 @@ function buildPhoenixGlobalConfigPayload() {
lrFractionalDelaySamples: Number.isFinite(CONFIG.LR_FRACTIONAL_DELAY_SAMPLES) ? CONFIG.LR_FRACTIONAL_DELAY_SAMPLES : (CONFIG_DEFAULTS.LR_FRACTIONAL_DELAY_SAMPLES ?? 0.996),
ppmDinAttackMs: 10,
ppmDinDecayDbPerS: 20 / 1.5,
ppmDinFastAttack: !!CONFIG.PPM_DIN_FAST_ATTACK,
ppmEbuAttackMs: 10,
ppmEbuDecayDbPerS: 24 / 2.8,
rmsIntegration,
lufsIWindowMin: Number.isFinite(CONFIG.LUFS_I_WINDOW_MIN) ? CONFIG.LUFS_I_WINDOW_MIN : (CONFIG_DEFAULTS.LUFS_I_WINDOW_MIN ?? 4),
lufsINormEnabled: !!CONFIG.LUFS_I_NORM_ENABLED,
ppmDinLoudnessBoxes: !!CONFIG.PPM_DIN_LOUDNESS_BOXES,
@@ -1162,9 +1167,12 @@ function applyPhoenixGlobalConfig(payload = {}) {
if ('spectroScrollMode' in payload) CONFIG.SPECTRO_SCROLL_MODE = normalizeSpectroScroll(payload.spectroScrollMode);
CONFIG.PPM_DIN_ATTACK_MS = 10;
CONFIG.PPM_DIN_DECAY_DB_PER_S = 20 / 1.5;
if ('ppmDinFastAttack' in payload) CONFIG.PPM_DIN_FAST_ATTACK = !!payload.ppmDinFastAttack;
CONFIG.PPM_EBU_ATTACK_MS = 10;
CONFIG.PPM_EBU_DECAY_DB_PER_S = 24 / 2.8;
if ('rmsIntegration' in payload) {
const mode = String(payload.rmsIntegration || '').trim().toLowerCase();
CONFIG.RMS_TC_MODE = (mode === 'slow' || mode === 'window') ? mode : 'fast';
}
const lufsWin = Number(payload.lufsIWindowMin);
if (Number.isFinite(lufsWin)) CONFIG.LUFS_I_WINDOW_MIN = Math.max(1, Math.min(10, Math.round(lufsWin)));
if ('lufsINormEnabled' in payload) CONFIG.LUFS_I_NORM_ENABLED = !!payload.lufsINormEnabled;
@@ -1297,7 +1305,7 @@ function applyBroadcastStandard(name) {
CONFIG.VU_RED_START = p.VU_RED_START;
// Offsets zurücksetzen (wie bisher)
CONFIG.VU_OFFSET_DB = VU_OFFSET_ALIGNMENT_DB;
CONFIG.VU_OFFSET_DB = VU_OFFSET_DEFAULT_DB;
CONFIG.TP_OFFSET_DB = 0;
CONFIG.RMS_OFFSET_DB = 0;