Correct audio metering and realtime displays
This commit is contained in:
+13
-1
@@ -444,6 +444,11 @@ async function applyIncomingAudioPacket(env, packet, CONFIG, sampleTs = performa
|
||||
if (typeof d.correlationNegativePeak === 'number') {
|
||||
env.audio.correlationNegativePeak = d.correlationNegativePeak;
|
||||
}
|
||||
env.audio.phaseAngleRad = typeof d.phaseAngleRad === 'number' ? d.phaseAngleRad : null;
|
||||
env.audio.phaseSeq = Number.isFinite(seq) ? seq : ((env.audio.phaseSeq || 0) + 1);
|
||||
if (typeof d.phaseCoherence === 'number') env.audio.phaseCoherence = d.phaseCoherence;
|
||||
if (typeof d.phaseLevel === 'number') env.audio.phaseLevel = d.phaseLevel;
|
||||
if (typeof d.phasePeak === 'number') env.audio.phasePeak = d.phasePeak;
|
||||
if (d.waveL && env.audio.pushWaveSamples) {
|
||||
const channelCount = d.waveChannels || (d.waveR ? 2 : 1);
|
||||
env.audio.sampleRate = d.sampleRate || env.audio.sampleRate || 48000;
|
||||
@@ -502,6 +507,10 @@ function buildPhoenixMeterPacket(frame) {
|
||||
const ppmBoxR = Number(frame?.ppm_box_r);
|
||||
const correlation = Number(frame?.correlation);
|
||||
const correlationNegativePeak = Number(frame?.correlation_negative_peak);
|
||||
const phaseAngleRad = Number(frame?.phase_angle_rad);
|
||||
const phaseCoherence = Number(frame?.phase_coherence);
|
||||
const phaseLevel = Number(frame?.phase_level);
|
||||
const phasePeak = Number(frame?.phase_peak);
|
||||
const xyL = Array.isArray(frame?.xy_l) ? frame.xy_l : null;
|
||||
const xyR = Array.isArray(frame?.xy_r) ? frame.xy_r : null;
|
||||
const waveL = Array.isArray(frame?.wave_l) && frame.wave_l.length ? frame.wave_l : null;
|
||||
@@ -515,6 +524,10 @@ function buildPhoenixMeterPacket(frame) {
|
||||
correlationNegativePeak: Number.isFinite(correlationNegativePeak)
|
||||
? Math.max(-1, Math.min(1, correlationNegativePeak))
|
||||
: 0,
|
||||
phaseAngleRad: Number.isFinite(phaseAngleRad) ? phaseAngleRad : null,
|
||||
phaseCoherence: Number.isFinite(phaseCoherence) ? Math.max(0, Math.min(1, phaseCoherence)) : 0,
|
||||
phaseLevel: Number.isFinite(phaseLevel) ? Math.max(0, phaseLevel) : 0,
|
||||
phasePeak: Number.isFinite(phasePeak) ? Math.max(0, phasePeak) : 0,
|
||||
rmsL: Number.isFinite(rmsL) ? rmsL : -120,
|
||||
rmsR: Number.isFinite(rmsR) ? rmsR : -120,
|
||||
tpL: Number.isFinite(tpL) ? tpL : -120,
|
||||
@@ -926,7 +939,6 @@ export function buildRtaRuntimeConfig(CONFIG = {}) {
|
||||
inputOffsetDbR: Number.isFinite(CONFIG.INPUT_OFFSET_DB_R) ? CONFIG.INPUT_OFFSET_DB_R : -5,
|
||||
ppmDinAttackMs: 10,
|
||||
ppmDinDecayDbPerS: 20 / 1.5,
|
||||
ppmDinFastAttack: !!CONFIG.PPM_DIN_FAST_ATTACK,
|
||||
ppmEbuAttackMs: 10,
|
||||
ppmEbuDecayDbPerS: 24 / 2.8,
|
||||
lufsIWindowMin: Number.isFinite(CONFIG.LUFS_I_WINDOW_MIN) ? CONFIG.LUFS_I_WINDOW_MIN : 4,
|
||||
|
||||
+28
-20
@@ -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 Peak‑Hold
|
||||
// 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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user