backing tracks: add source selector + bluealsa in device list

- Audio devices endpoint now includes Bluetooth Audio (bluealsa) and
  other software PCM devices from aplay -L
- Added GET/POST /api/backing-source endpoints with JACK port routing
- Backing Track Source dropdown in Audio section (None, Bluetooth
  Audio, or any JACK capture port found)
- Selecting a source routes it into fx_in:input_2 via jack_connect
- Also supports bt_audio:capture_1/2 from existing JACK bridge
This commit is contained in:
2026-06-16 19:20:30 -04:00
parent 334e035cde
commit a37e381c4e
2 changed files with 97 additions and 1 deletions
+28 -1
View File
@@ -281,6 +281,11 @@ body{display:flex;flex-direction:column;max-height:100vh;user-select:none;-webki
<div class="setting-row"><span class="sr-label">🎸 Instrument</span><span class="sr-value" id="instrumentLabel">Guitar</span><button class="sr-action" id="instrumentCycleBtn" style="min-width:44px;padding:4px 10px">Cycle</button></div>
<div class="setting-row"><span class="sr-label">🔄 Channel Mode</span><span class="sr-value" id="channelModeLabel">Dual Mono</span><button class="sr-action" id="channelModeToggle">Toggle</button></div>
<div class="setting-row"><span class="sr-label">🔗 Routing</span><span class="sr-value" id="routingModeLabel">4CM</span><button class="sr-action" id="routingModeToggle">Toggle</button></div>
<div class="setting-row"><span class="sr-label">🎵 Backing Track</span>
<select id="backingSource" onchange="setBackingSource(this.value)" style="flex:1;max-width:160px;font-size:10px;padding:4px 6px;min-height:30px;border-radius:6px;border:1px solid var(--border);background:var(--surface);color:var(--text);font-family:var(--font)">
<option value="none">None</option>
</select>
</div>
</div>
<div class="setting-group" id="section-interface"><div class="setting-group-title">🎚 Audio Interface</div>
<div class="setting-row"><span class="sr-label">🔌 Input Device</span><select id="audioInputDevice" onchange="setAudioInputDevice(this.value)" style="flex:1;min-width:0;font-size:10px;padding:4px 6px;min-height:30px"><option value="">Loading...</option></select></div>
@@ -518,6 +523,27 @@ async function loadChOutput(){
if(r.ch2){const el=document.getElementById('ch2Output');if(el)el.value=r.ch2;}
}catch(e){}
}
async function loadBackingSource(){
try{
const r=await API._fetch('/api/backing-source');
const sel=document.getElementById('backingSource');
if(!sel)return;
sel.innerHTML='';
(r.sources||[]).forEach(s=>{
const o=document.createElement('option');
o.value=s.id;o.textContent=s.name;
if(s.id===r.current)o.selected=true;
sel.appendChild(o);
});
}catch(e){}
}
async function setBackingSource(source){
if(!source)return;
try{
await API._fetch('/api/backing-source',{method:'POST',body:JSON.stringify({source})});
toast('Backing: '+source);
}catch(e){toast('Failed: '+e.message);}
}
function setChInstrument(idx,val){
const arr=JSON.parse(localStorage.getItem('chInstruments')||'["guitar","bass"]');
arr[idx]=val;
@@ -875,7 +901,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();loadChOutput();loadHotspotStatus();loadBtStatus();loadBtMidi();return;}
else if(view==='settings'){openOverlay('Settings');loadNetworkInfo();loadSystemInfo();loadAudioParams();loadAudioDevices();loadChOutput();loadBackingSource();loadHotspotStatus();loadBtStatus();loadBtMidi();return;}
else if(view==='presets'){openOverlay('Presets');loadPresets();}
else if(view==='snapshots'){openOverlay('Snapshots');loadSnapshots();}
else if(view==='downloads')openOverlay('Downloads');
@@ -890,6 +916,7 @@ function init(){
loadAudioParams();
loadAudioDevices();
loadChOutput();
loadBackingSource();
loadHotspotStatus();
loadBtStatus();
loadBtMidi();