From e318647d3ba5a48e3db5b3766727ddf21bd7c494 Mon Sep 17 00:00:00 2001 From: Mikei386 <44135113+Mikei386@users.noreply.github.com> Date: Tue, 21 Jul 2026 20:13:04 +0200 Subject: [PATCH] Add 3.8 changelog and fix RTA octave selection --- scripts/test_rta_profile.mjs | 15 +++++++++++++++ src/state.rs | 13 +++++++++++++ www/core/config.js | 17 ++++++++++++++++- www/index.html | 30 +++++++++++++++++++++++++++--- www/main.js | 5 +++-- www/ui/options.js | 9 ++++----- 6 files changed, 78 insertions(+), 11 deletions(-) diff --git a/scripts/test_rta_profile.mjs b/scripts/test_rta_profile.mjs index cdbaaef..8ff4df3 100644 --- a/scripts/test_rta_profile.mjs +++ b/scripts/test_rta_profile.mjs @@ -44,4 +44,19 @@ assert.equal(extension.bpo, '1_12'); assert.equal(extension.freqRange, 'lf'); assert.equal(extension.order, 8); +const configSource = fs.readFileSync(new URL('../www/core/config.js', import.meta.url), 'utf8'); +const selectionSource = configSource.match(/function applyRtaBpoSelection[\s\S]*?\n\}/)?.[0]; +assert.ok(selectionSource, 'RTA BPO selection policy must remain testable'); +const selectionContext = vm.createContext({ + String, + CONFIG: { RTA_BPO_MODE: '1_3', RTA_BAR_LAYOUT: 'rtw' }, +}); +vm.runInContext(selectionSource, selectionContext); +assert.equal(selectionContext.applyRtaBpoSelection('1_6'), '1_6'); +assert.equal(selectionContext.CONFIG.RTA_BPO_MODE, '1_6'); +assert.equal(selectionContext.CONFIG.RTA_BAR_LAYOUT, 'iec'); +selectionContext.CONFIG.RTA_BAR_LAYOUT = 'rtw'; +assert.equal(selectionContext.applyRtaBpoSelection('1_3'), '1_3'); +assert.equal(selectionContext.CONFIG.RTA_BAR_LAYOUT, 'rtw'); + console.log('RTA profile regression tests passed'); diff --git a/src/state.rs b/src/state.rs index 6f5f272..815ee23 100644 --- a/src/state.rs +++ b/src/state.rs @@ -663,6 +663,9 @@ fn apply_global_to_rta( ) -> PhoenixRtaConfig { config.fft_size = global.fft_size; config.bpo = global.rta_bpo_mode.clone(); + if config.bpo != "1_3" && config.layout == "rtw" { + config.layout = "iec".to_string(); + } config.input_offset_db_l = global.input_offset_db_l; config.input_offset_db_r = global.input_offset_db_r; config.mono_input = global.mono_input; @@ -744,4 +747,14 @@ mod tests { assert_eq!(config.freq_range, "lf"); assert_eq!(config.integration, "medium"); } + + #[test] + fn non_third_octave_global_selection_leaves_locked_rtw_profile() { + let mut global = PhoenixGlobalConfig::default(); + global.rta_bpo_mode = "1_12".to_string(); + let config = apply_global_to_rta(PhoenixRtaConfig::default(), &global); + assert_eq!(config.layout, "iec"); + assert_eq!(config.bpo, "1_12"); + assert_eq!(config.engine, "iir"); + } } diff --git a/www/core/config.js b/www/core/config.js index cdb8ce4..3289a81 100644 --- a/www/core/config.js +++ b/www/core/config.js @@ -281,6 +281,17 @@ const CONFIG = { SOFTWARE_PRESET: 'default', }; const CONFIG_DEFAULTS = JSON.parse(JSON.stringify(CONFIG)); + +function applyRtaBpoSelection(value) { + const mode = ['1_3', '1_6', '1_12'].includes(String(value)) ? String(value) : '1_3'; + CONFIG.RTA_BPO_MODE = mode; + // RTW remains the original 31-band third-octave reference profile. Finer + // resolutions are Phoenix extensions and switch visibly to the IEC profile. + if (mode !== '1_3' && CONFIG.RTA_BAR_LAYOUT === 'rtw') { + CONFIG.RTA_BAR_LAYOUT = 'iec'; + } + return mode; +} const SOFTWARE_PRESET_IDS = Object.freeze(['default', 'claus', 'michael']); const LAYOUT_PRESET_IDS = Object.freeze(['1', '2', '3', '4']); const LAYOUT_PRESET_KEYS = Object.freeze([ @@ -778,6 +789,9 @@ function loadConfig(opts = {}) { if (typeof saved.PPM_DIN_DECAY_DB_PER_S === 'number') CONFIG.PPM_DIN_DECAY_DB_PER_S = saved.PPM_DIN_DECAY_DB_PER_S; if (typeof saved.PPM_DIN_HOLD_MS === 'number') CONFIG.PPM_DIN_HOLD_MS = saved.PPM_DIN_HOLD_MS; if (CONFIG.RTA_BAR_LAYOUT === 'classic') CONFIG.RTA_BAR_LAYOUT = 'rtw'; + if (CONFIG.RTA_BAR_LAYOUT === 'rtw' && CONFIG.RTA_BPO_MODE !== '1_3') { + CONFIG.RTA_BAR_LAYOUT = 'iec'; + } if (CONFIG.RTA_BAR_LAYOUT === 'rtw') { CONFIG.RTA_ENGINE = 'iir'; CONFIG.RTA_BPO_MODE = '1_3'; @@ -1108,7 +1122,7 @@ function applyPhoenixGlobalConfig(payload = {}) { } if ('rtaBpoMode' in payload) { const mode = String(payload.rtaBpoMode || '').trim(); - CONFIG.RTA_BPO_MODE = (mode === '1_3' || mode === '1_6' || mode === '1_12') ? mode : '1_6'; + applyRtaBpoSelection(mode); } if (CONFIG.RTA_BAR_LAYOUT === 'rtw') { CONFIG.RTA_ENGINE = 'iir'; @@ -1278,6 +1292,7 @@ export { saveConfig, buildPhoenixGlobalConfigPayload, applyPhoenixGlobalConfig, + applyRtaBpoSelection, applyBroadcastStandard, applySoftwarePreset, loadSoftwarePreset, diff --git a/www/index.html b/www/index.html index 4118680..0c9d15a 100644 --- a/www/index.html +++ b/www/index.html @@ -310,7 +310,7 @@ - Filterauflösung – Anzahl Bänder + RTW verwendet fest 1/3; 1/6 und 1/12 wechseln automatisch zum IEC-/Phoenix-Profil.
@@ -1245,8 +1245,32 @@

Version / Änderungen -
-
+
+
+ 3.8 (Phoenix 1.0) +
+
+

Veröffentlichung: 21.07.2026

+

Änderungen:

+
    +
  • Analysegrundlage: Die tiefgehende Code- und DSP-Prüfung, durch die die nachfolgenden Fehler und Verbesserungsmöglichkeiten gefunden werden konnten, wurde durch den Umstieg auf das LLM-Modell GPT-5.6 SOL ermöglicht.
  • +
  • Echtzeit-Datenweg: WebSocket-Verarbeitung auf „latest value wins“ umgestellt. Messwerte, Spektrogramm sowie Goniometer/Waveform verwenden getrennte, begrenzte Datenwege; alte Frames können keine anwachsende Anzeigeverzögerung mehr bilden.
  • +
  • Browserlast: Single-Slot-Puffer und Sequenzprüfung für Mess-, Spektrogramm- und Visualisierungsdaten ergänzt. Große Rohsamplefelder werden nicht mehr in jedem JSON-Messpaket wiederholt.
  • +
  • Spektrogramm: Langzeitstillstand und stotterndes Nachholen beseitigt. Inkrementelles Spaltenzeichnen, Worker-ACK, Watchdog/Neustart und begrenztes Überspringen veralteter Spalten ergänzt. 0,5×, 1×, 2×, 4× und 6× besitzen nun eine feste, FFT- und DPI-unabhängige Zeitbasis.
  • +
  • DIN-/EBU-PPM: Blockunabhängige Quasi-Peak-Detektoren mit bandbegrenzter Interpolation, korrekter Attack- und Rücklaufballistik sowie automatischen Tonburst-, Frequenzgang- und Polaritätstests implementiert. Eine zweite Browser-Anstiegsballistik wurde entfernt.
  • +
  • RTW-RTA: RTW-Profil verbindlich auf die IIR-Dritteloktav-Filterbank festgelegt. Die Filterbank verwendet vollständige Butterworth-Bandpässe sechster Ordnung aus unterschiedlichen SOS-Sektionen, interne f64-Rechnung sowie exakte IEC-Basis-10-Mitten und -Bandkanten bei vertrauten Nominalbeschriftungen.
  • +
  • RTA-Bewertung und Integration: A-, C- und Z-Bewertung sampleweise vor der Filterbank ergänzt. Fast, Medium, Slow, Impulse, Average und Peak rechnen im Leistungsbereich und unabhängig von der ALSA-Periodengröße.
  • +
  • RTA-Auflösung: Umschaltung zwischen 1/3, 1/6 und 1/12 repariert. 1/6 und 1/12 wechseln sichtbar in das IEC-/Phoenix-Erweiterungsprofil; das originale RTW-Profil bleibt korrekt auf 1/3 verriegelt.
  • +
  • Hardwareparameter: Tatsächlich von ALSA ausgehandelte Samplerate, Perioden- und Puffergröße werden nun durch DSP, Aufnahme, Status und Browser verwendet; die feste 48-kHz-Annahme wurde entfernt.
  • +
  • Goniometer: Nur neue XY-Samplepaare werden mit einer periodengrößenunabhängigen mittleren Rate von 60 Hz übertragen. Punktbegrenzung wirkt bereits auf den Transport; begrenzte und wiederverwendbare Spurpuffer reduzieren Speicher- und Zeichenlast.
  • +
  • Goniometer-Persistenz: Reproduzierbare Fast-, Medium- und Slow-Profile sowie ein freies Phoenix-Fade ergänzt. Künstliche Bézier-Verformung der Messspur entfernt; AGC und Silence-Gate arbeiten zeit- beziehungsweise fensterbasiert.
  • +
  • Korrelation: Kontinuierliche DSP-Messung aus L², R² und L·R mit wählbaren 1,0/2,5 Sekunden ergänzt. Bildratenabhängige Doppelglättung entfernt; Negative-Peak-Memory, Marker und manueller Reset hinzugefügt.
  • +
  • Qualitätssicherung: Automatische Regressionstests für PPM, RTA, A/C/Z, mehrere Sampleraten, Korrelationssignale, Goniometertaktung, Binärprotokolle sowie Spektrogramm-Zeitbasis und Langlauf ergänzt.
  • +
+
+
+
+
3.3.5 (Phoenix 1.0)
diff --git a/www/main.js b/www/main.js index a30a707..708cef1 100644 --- a/www/main.js +++ b/www/main.js @@ -20,7 +20,7 @@ try { } } catch(_) {} -import { CONFIG, loadConfig, saveConfig, loadLayoutPreset } from './core/config.js'; +import { CONFIG, applyRtaBpoSelection, loadConfig, saveConfig, loadLayoutPreset } from './core/config.js'; import * as utils from './core/utils.js'; import { meterFacade, registerMeter } from './core/registry.js'; import { initAudio, audioLost, reloadAudio } from './core/audio.js'; @@ -2152,7 +2152,7 @@ function handlePeakHistScrollSelection(value){ function handleRtaBpoSelection(value){ const mode = normalizeRtaBpo(value); - CONFIG.RTA_BPO_MODE = mode; + applyRtaBpoSelection(mode); saveConfig(); if (rtaBpoSel) { rtaBpoSel.value = mode; @@ -2162,6 +2162,7 @@ function handleRtaBpoSelection(value){ select.value = mode; } try { env.audio.updateRtaConfig?.(); } catch (_) {} + try { env.audio.updatePhoenixGlobalConfig?.(); } catch (_) {} } function getNearestWaveWindow(value){ diff --git a/www/ui/options.js b/www/ui/options.js index 09986ae..ed7875b 100644 --- a/www/ui/options.js +++ b/www/ui/options.js @@ -1,7 +1,7 @@ // ui/options.js — bindet das Options-Panel an CONFIG (lesen/schreiben), Presets, Export/Import // Erwartet vorhandenes DOM aus index.html. Nutzt localStorage-Key 'analyzer_config'. -import { CONFIG, saveConfig, loadConfig, applyAlignmentProfile, applySoftwarePreset, loadSoftwarePreset, saveSoftwarePreset, loadLayoutPreset, saveLayoutPreset, exportSoftwarePreset, importSoftwarePreset, updateVuReference, resetConfigToDefaults, updateInputOffsetGain } from '../core/config.js'; +import { CONFIG, saveConfig, loadConfig, applyAlignmentProfile, applyRtaBpoSelection, applySoftwarePreset, loadSoftwarePreset, saveSoftwarePreset, loadLayoutPreset, saveLayoutPreset, exportSoftwarePreset, importSoftwarePreset, updateVuReference, resetConfigToDefaults, updateInputOffsetGain } from '../core/config.js'; import { clamp, clampPow2 } from '../core/utils.js'; // DOM helper @@ -1075,10 +1075,9 @@ function wireHandlers(env) { return CONFIG.RTA_ENGINE; }); h('opt_rtaBpo', v => { - const allowed = new Set(['1_3', '1_6', '1_12']); - CONFIG.RTA_BPO_MODE = CONFIG.RTA_BAR_LAYOUT === 'rtw' - ? '1_3' - : (allowed.has(v) ? v : '1_6'); + applyRtaBpoSelection(v); + const layoutControl = E('opt_rtaLayout'); + if (layoutControl) layoutControl.value = CONFIG.RTA_BAR_LAYOUT; notifyPhoenixGlobalConfig(); return CONFIG.RTA_BPO_MODE; });