|
|
@@ -404,7 +404,7 @@ input.input-error{border-color:var(--red);box-shadow:0 0 0 3px rgba(176,48,48,.1 |
|
|
<div class="toggle-ctl"><select id="sel-stereo-mode" style="font-size:13px;padding:4px 8px;border-radius:6px;border:1px solid var(--border);background:var(--bg-card);color:var(--fg)"><option value="DSB">DSB-SC (Standard)</option><option value="SSB">SSB-SC LSB</option><option value="VSB">VSB (Vestigial)</option></select></div> |
|
|
<div class="toggle-ctl"><select id="sel-stereo-mode" style="font-size:13px;padding:4px 8px;border-radius:6px;border:1px solid var(--border);background:var(--bg-card);color:var(--fg)"><option value="DSB">DSB-SC (Standard)</option><option value="SSB">SSB-SC LSB</option><option value="VSB">VSB (Vestigial)</option></select></div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="toggle-row"> |
|
|
<div class="toggle-row"> |
|
|
<div class="toggle-copy"><div class="title">Limiter</div><div class="sub">MPX peak protection</div></div> |
|
|
|
|
|
|
|
|
<div class="toggle-copy"><div class="title">Limiter</div><div class="sub">Stereo limiter stage only; hard clips remain active</div></div> |
|
|
<div class="toggle-ctl"><div class="toggle" id="tog-limiter" data-toggle="limiterEnabled" role="switch" aria-checked="false" tabindex="0"></div><div class="toggle-state" id="limiter-label">--</div></div> |
|
|
<div class="toggle-ctl"><div class="toggle" id="tog-limiter" data-toggle="limiterEnabled" role="switch" aria-checked="false" tabindex="0"></div><div class="toggle-state" id="limiter-label">--</div></div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
@@ -515,9 +515,9 @@ input.input-error{border-color:var(--red);box-shadow:0 0 0 3px rgba(176,48,48,.1 |
|
|
</div> |
|
|
</div> |
|
|
<!-- On-Air Text --> |
|
|
<!-- On-Air Text --> |
|
|
<div class="card panel" data-panel-key="rds-text"> |
|
|
<div class="card panel" data-panel-key="rds-text"> |
|
|
<div class="panel-head" data-panel><div class="led on-green" style="width:6px;height:6px"></div><h2>On-Air Text</h2><div class="meta" id="rds-text-meta">Live + Saved</div><span class="chevron">▼</span></div> |
|
|
|
|
|
|
|
|
<div class="panel-head" data-panel><div class="led on-green" style="width:6px;height:6px"></div><h2>On-Air Text</h2><div class="meta" id="rds-text-meta">Saved + Runtime</div><span class="chevron">▼</span></div> |
|
|
<div class="panel-body"> |
|
|
<div class="panel-body"> |
|
|
<div class="section-note">PS and RadioText apply at the next RDS group boundary (~88ms). Edits stay local until you apply, then update the live encoder and config snapshot together.</div> |
|
|
|
|
|
|
|
|
<div class="section-note">PS and RadioText apply at the next RDS group boundary (~88ms). Edits stay local until you apply, then update the live encoder and config snapshot together. When StreamTitle relay is enabled, the active on-air RadioText can temporarily differ from the saved config value shown in the editor.</div> |
|
|
<div class="preset-row"> |
|
|
<div class="preset-row"> |
|
|
<button class="preset-btn rds" type="button" data-rds-ps="FMRTX" data-rds-rt="fm-rds-tx live">Station ID</button> |
|
|
<button class="preset-btn rds" type="button" data-rds-ps="FMRTX" data-rds-rt="fm-rds-tx live">Station ID</button> |
|
|
<button class="preset-btn rds" type="button" data-rds-ps="ONAIR" data-rds-rt="Now broadcasting">On Air</button> |
|
|
<button class="preset-btn rds" type="button" data-rds-ps="ONAIR" data-rds-rt="Now broadcasting">On Air</button> |
|
|
@@ -539,6 +539,7 @@ input.input-error{border-color:var(--red);box-shadow:0 0 0 3px rgba(176,48,48,.1 |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="actions-row"><button class="apply-btn" id="rds-apply" type="button">Apply + Save RDS Text</button><button class="apply-btn secondary" id="rds-reset" type="button">Reset Draft</button></div> |
|
|
<div class="actions-row"><button class="apply-btn" id="rds-apply" type="button">Apply + Save RDS Text</button><button class="apply-btn secondary" id="rds-reset" type="button">Reset Draft</button></div> |
|
|
|
|
|
<div class="section-note">Saved config: <span id="rds-saved-rt">--</span><br>Active on-air text: <span id="rds-active-rt-inline">--</span></div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<!-- RDS Features --> |
|
|
<!-- RDS Features --> |
|
|
@@ -636,7 +637,8 @@ input.input-error{border-color:var(--red);box-shadow:0 0 0 3px rgba(176,48,48,.1 |
|
|
<div class="k">PI Code</div><div class="v" id="rds-stat-pi" style="font-family:var(--mono);font-weight:700">--</div> |
|
|
<div class="k">PI Code</div><div class="v" id="rds-stat-pi" style="font-family:var(--mono);font-weight:700">--</div> |
|
|
<div class="k">PTY</div><div class="v" id="rds-stat-pty">--</div> |
|
|
<div class="k">PTY</div><div class="v" id="rds-stat-pty">--</div> |
|
|
<div class="k">PS</div><div class="v" id="rds-stat-ps" style="font-family:var(--mono);font-weight:700;letter-spacing:1px">--</div> |
|
|
<div class="k">PS</div><div class="v" id="rds-stat-ps" style="font-family:var(--mono);font-weight:700;letter-spacing:1px">--</div> |
|
|
<div class="k">RadioText</div><div class="v" id="rds-stat-rt">--</div> |
|
|
|
|
|
|
|
|
<div class="k">Active RadioText</div><div class="v" id="rds-stat-rt">--</div> |
|
|
|
|
|
<div class="k">Saved RadioText</div><div class="v" id="rds-stat-rt-saved">--</div> |
|
|
<div class="k">Pilot</div><div class="v" id="rds-stat-pilot">--</div> |
|
|
<div class="k">Pilot</div><div class="v" id="rds-stat-pilot">--</div> |
|
|
<div class="k">RDS Inj.</div><div class="v" id="rds-stat-inj">--</div> |
|
|
<div class="k">RDS Inj.</div><div class="v" id="rds-stat-inj">--</div> |
|
|
</div> |
|
|
</div> |
|
|
@@ -1014,7 +1016,7 @@ function _render(){ |
|
|
setText('info-pi',fmtPI(cfg.rds?.pi));setText('info-pty',fmtPTY(cfg.rds?.pty)); |
|
|
setText('info-pi',fmtPI(cfg.rds?.pi));setText('info-pty',fmtPTY(cfg.rds?.pty)); |
|
|
setText('info-runtime-age',ageStr(S.server.lastRuntimeAt));setText('info-last-alert',eng.runtimeAlert||eng.lastError||'None'); |
|
|
setText('info-runtime-age',ageStr(S.server.lastRuntimeAt));setText('info-last-alert',eng.runtimeAlert||eng.lastError||'None'); |
|
|
setText('info-drive',cfg.fm?.outputDrive!=null?Number(cfg.fm.outputDrive).toFixed(2):'--'); |
|
|
setText('info-drive',cfg.fm?.outputDrive!=null?Number(cfg.fm.outputDrive).toFixed(2):'--'); |
|
|
setText('info-limiter',cfg.fm?.limiterEnabled?(cfg.fm?.limiterCeiling!=null?`ON (ceil ${Number(cfg.fm.limiterCeiling).toFixed(2)})`:'ON'):'OFF'); |
|
|
|
|
|
|
|
|
setText('info-limiter',cfg.fm?.limiterEnabled?(cfg.fm?.limiterCeiling!=null?`Limiter ON · clips always active · ceil ${Number(cfg.fm.limiterCeiling).toFixed(2)}`:'Limiter ON · clips always active'):'Limiter OFF · hard clips still active'); |
|
|
setText('info-pilot',fmtPilot(cfg.fm?.pilotLevel));setText('info-rdsinj',fmtPilot(cfg.fm?.rdsInjection)); |
|
|
setText('info-pilot',fmtPilot(cfg.fm?.pilotLevel));setText('info-rdsinj',fmtPilot(cfg.fm?.rdsInjection)); |
|
|
setText('info-mpxgain',cfg.fm?.mpxGain!=null?Number(cfg.fm.mpxGain).toFixed(2):'--'); |
|
|
setText('info-mpxgain',cfg.fm?.mpxGain!=null?Number(cfg.fm.mpxGain).toFixed(2):'--'); |
|
|
setText('info-bs412',cfg.fm?.bs412Enabled?`ON (${cfg.fm?.bs412ThresholdDBr??0} dBr)`:'OFF'); |
|
|
setText('info-bs412',cfg.fm?.bs412Enabled?`ON (${cfg.fm?.bs412ThresholdDBr??0} dBr)`:'OFF'); |
|
|
@@ -1073,7 +1075,7 @@ function _render(){ |
|
|
syncDirtyInput('rds-ps','ps',v=>String(v??''));syncDirtyInput('rds-rt','radioText',v=>String(v??'')); |
|
|
syncDirtyInput('rds-ps','ps',v=>String(v??''));syncDirtyInput('rds-rt','radioText',v=>String(v??'')); |
|
|
const psV=String(effVal('ps')??cfg.rds?.ps??''),rtV=String(effVal('radioText')??cfg.rds?.radioText??''); |
|
|
const psV=String(effVal('ps')??cfg.rds?.ps??''),rtV=String(effVal('radioText')??cfg.rds?.radioText??''); |
|
|
setText('ps-count',psV.length);setText('rt-count',rtV.length); |
|
|
setText('ps-count',psV.length);setText('rt-count',rtV.length); |
|
|
const rdsD=secDirty('rds');setText('rds-text-meta',secErrors('rds')?'Validation error':rdsD?'Draft pending':'Live + Saved'); |
|
|
|
|
|
|
|
|
const rdsD=secDirty('rds');setText('rds-text-meta',secErrors('rds')?'Validation error':rdsD?'Draft pending':'Saved + Runtime'); |
|
|
$('rds-apply').disabled=!rdsD||secErrors('rds');$('rds-reset').disabled=!rdsD; |
|
|
$('rds-apply').disabled=!rdsD||secErrors('rds');$('rds-reset').disabled=!rdsD; |
|
|
const psErr=$('ps-error');if(psErr){psErr.textContent=S.errors.ps||'';psErr.classList.toggle('show',!!S.errors.ps);} |
|
|
const psErr=$('ps-error');if(psErr){psErr.textContent=S.errors.ps||'';psErr.classList.toggle('show',!!S.errors.ps);} |
|
|
const rtErr=$('rt-error');if(rtErr){rtErr.textContent=S.errors.radioText||'';rtErr.classList.toggle('show',!!S.errors.radioText);} |
|
|
const rtErr=$('rt-error');if(rtErr){rtErr.textContent=S.errors.radioText||'';rtErr.classList.toggle('show',!!S.errors.radioText);} |
|
|
@@ -1102,8 +1104,9 @@ function _render(){ |
|
|
// Status card |
|
|
// Status card |
|
|
const activePS=String(eng.activePS||cfg.rds?.ps||'').trim(); |
|
|
const activePS=String(eng.activePS||cfg.rds?.ps||'').trim(); |
|
|
const activeRT=String(eng.activeRadioText||cfg.rds?.radioText||'').trim(); |
|
|
const activeRT=String(eng.activeRadioText||cfg.rds?.radioText||'').trim(); |
|
|
|
|
|
const savedRT=String(cfg.rds?.radioText||'').trim(); |
|
|
setText('rds-stat-enabled',cfg.rds?.enabled?'ON':'OFF');setText('rds-stat-pi',fmtPI(cfg.rds?.pi)); |
|
|
setText('rds-stat-enabled',cfg.rds?.enabled?'ON':'OFF');setText('rds-stat-pi',fmtPI(cfg.rds?.pi)); |
|
|
setText('rds-stat-pty',fmtPTY(cfg.rds?.pty));setText('rds-stat-ps',activePS||'--');setText('rds-stat-rt',activeRT||'--'); |
|
|
|
|
|
|
|
|
setText('rds-stat-pty',fmtPTY(cfg.rds?.pty));setText('rds-stat-ps',activePS||'--');setText('rds-stat-rt',activeRT||'--');setText('rds-stat-rt-saved',savedRT||'--');setText('rds-saved-rt',savedRT||'--');setText('rds-active-rt-inline',activeRT||'--'); |
|
|
setText('rds-stat-pilot',fmtPilot(cfg.fm?.pilotLevel));setText('rds-stat-inj',fmtPilot(cfg.fm?.rdsInjection)); |
|
|
setText('rds-stat-pilot',fmtPilot(cfg.fm?.pilotLevel));setText('rds-stat-inj',fmtPilot(cfg.fm?.rdsInjection)); |
|
|
|
|
|
|
|
|
// ── Ingest tab |
|
|
// ── Ingest tab |
|
|
|