ch output: per-channel output routing dropdowns

- Added GET/POST /api/channel-output endpoints for per-channel
  output routing (playback_1 / playback_2 / both)
- Added output dropdowns to CH 1 and CH 2 cards in Audio Interface
- Added setChOutput() and loadChOutput() JS functions
- Updated connect_fx_ports to read per-channel output config
This commit is contained in:
2026-06-16 19:18:30 -04:00
parent e324d9007b
commit 334e035cde
2 changed files with 64 additions and 3 deletions
+31 -3
View File
@@ -300,7 +300,14 @@ body{display:flex;flex-direction:column;max-height:100vh;user-select:none;-webki
<option value="backing_tracks">📻 Backing</option>
</select>
</div>
<div style="font-size:9px;color:var(--text2);margin-top:2px">Output: Main L/R (Scarlett 1+2)</div>
<div style="font-size:9px;color:var(--text2);margin-top:2px;display:flex;align-items:center;justify-content:space-between">
<span>Output:</span>
<select id="ch1Output" onchange="setChOutput(1,this.value)" style="font-size:9px;padding:2px 4px;min-height:22px;border-radius:4px;border:1px solid var(--border);background:var(--surface);color:var(--text);font-family:var(--font)">
<option value="playback_1">Output 1 (L)</option>
<option value="playback_2">Output 2 (R)</option>
<option value="both" selected>Both (L+R)</option>
</select>
</div>
</div>
<div class="ch-card" id="ch2Card" style="background:var(--card2);border-radius:8px;padding:6px 8px;margin:4px 0;border:2px solid rgba(58,184,122,.25)">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px">
@@ -317,7 +324,14 @@ body{display:flex;flex-direction:column;max-height:100vh;user-select:none;-webki
<option value="backing_tracks">📻 Backing</option>
</select>
</div>
<div style="font-size:9px;color:var(--text2);margin-top:2px">Output: Main L/R (Scarlett 1+2)</div>
<div style="font-size:9px;color:var(--text2);margin-top:2px;display:flex;align-items:center;justify-content:space-between">
<span>Output:</span>
<select id="ch2Output" onchange="setChOutput(2,this.value)" style="font-size:9px;padding:2px 4px;min-height:22px;border-radius:4px;border:1px solid var(--border);background:var(--surface);color:var(--text);font-family:var(--font)">
<option value="playback_1">Output 1 (L)</option>
<option value="playback_2">Output 2 (R)</option>
<option value="both" selected>Both (L+R)</option>
</select>
</div>
</div>
<div style="font-size:9px;color:var(--text3);padding:2px 0">Dual Mono: each channel has independent presets. Same instrument = shared presets.</div>
</div>
@@ -491,6 +505,19 @@ async function setAudioOutputDevice(id){
hideLoading();
toast('Output: '+id);
}
async function setChOutput(ch,port){
try{
await API._fetch('/api/channel-output',{method:'POST',body:JSON.stringify({ch,port})});
toast('CH'+ch+': '+port);
}catch(e){toast('Failed: '+e.message);}
}
async function loadChOutput(){
try{
const r=await API._fetch('/api/channel-output');
if(r.ch1){const el=document.getElementById('ch1Output');if(el)el.value=r.ch1;}
if(r.ch2){const el=document.getElementById('ch2Output');if(el)el.value=r.ch2;}
}catch(e){}
}
function setChInstrument(idx,val){
const arr=JSON.parse(localStorage.getItem('chInstruments')||'["guitar","bass"]');
arr[idx]=val;
@@ -848,7 +875,7 @@ function init(){
btn.onclick=()=>{
const view=btn.dataset.view;
if(view==='main'){document.querySelectorAll('.tab-btn').forEach(b=>b.classList.remove('active'));btn.classList.add('active');}
else if(view==='settings'){openOverlay('Settings');loadNetworkInfo();loadSystemInfo();loadAudioParams();loadAudioDevices();loadHotspotStatus();loadBtStatus();loadBtMidi();return;}
else if(view==='settings'){openOverlay('Settings');loadNetworkInfo();loadSystemInfo();loadAudioParams();loadAudioDevices();loadChOutput();loadHotspotStatus();loadBtStatus();loadBtMidi();return;}
else if(view==='presets'){openOverlay('Presets');loadPresets();}
else if(view==='snapshots'){openOverlay('Snapshots');loadSnapshots();}
else if(view==='downloads')openOverlay('Downloads');
@@ -862,6 +889,7 @@ function init(){
loadSystemInfo();
loadAudioParams();
loadAudioDevices();
loadChOutput();
loadHotspotStatus();
loadBtStatus();
loadBtMidi();