audio: replace profiles with direct sample rate + buffer size controls

- Removed audio profile grid and preset cards
- Added two dropdowns: Sample Rate (44.1/48/96/192 kHz) and Buffer
  Size (64-2048 frames)
- New loadAudioParams() reads current rate+period from API
- New setAudioParams() POSTs {period, rate} directly on change
- Cleaned up unused CSS (.audio-profile-grid, .ap-card, .ap-key, etc.)
- Removed unused audioProfiles variable
This commit is contained in:
2026-06-16 19:11:21 -04:00
parent ea75c41745
commit 1530aa266f
+46 -37
View File
@@ -137,14 +137,6 @@ body{display:flex;flex-direction:column;max-height:100vh;user-select:none;-webki
.wifi-connect-pw input{flex:1;padding:6px 8px;border-radius:6px;border:1px solid var(--border);background:var(--surface);color:var(--text);font-family:var(--font);font-size:11px;outline:none;min-height:36px}
.wifi-connect-pw input:focus{border-color:var(--amber)}
.wifi-connect-pw button{min-width:52px;min-height:36px;border-radius:6px;border:1px solid var(--amber);background:var(--amber);color:#000;font-family:var(--font);font-size:11px;font-weight:700;cursor:pointer}
.audio-profile-grid{display:grid;grid-template-columns:1fr 1fr;gap:4px}
.ap-card{background:var(--surface);border:1px solid var(--border);border-radius:6px;padding:4px 6px;cursor:pointer;transition:all .12s;text-align:center}
.ap-card:active{transform:scale(.95)}
.ap-card.active{border-color:var(--amber);background:rgba(232,160,48,.08)}
.ap-card .ap-key{font-size:9px;font-weight:600;text-transform:capitalize;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ap-card .ap-desc{font-size:8px;color:var(--text2)}
.ap-card.loading{opacity:.5;pointer-events:none}
.ap-card.loading .ap-key::after{content:' ⟳';animation:spin .6s linear infinite;display:inline-block}
/* Loading overlay */
.loading-overlay{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:300;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:8px}
@@ -268,8 +260,24 @@ body{display:flex;flex-direction:column;max-height:100vh;user-select:none;-webki
<div class="setting-row"><span class="sr-label">🔥 Hotspot</span><span class="sr-value" id="hotspotStatus">Off</span><button class="sr-action" id="hotspotToggle">Enable</button></div>
</div>
<div class="setting-group" id="section-audio"><div class="setting-group-title">Audio</div>
<div class="setting-row"><span class="sr-label">🎛 Profile</span><span class="sr-value" id="audioProfileLabel"></span></div>
<div class="audio-profile-grid" id="audioProfileGrid"></div>
<div class="setting-row"><span class="sr-label">🎛 Sample Rate</span>
<select id="audioSampleRate" onchange="setAudioParams()" style="flex:1;max-width:140px;font-size:11px;padding:4px 8px;min-height:34px;border-radius:6px;border:1px solid var(--border);background:var(--surface);color:var(--text);font-family:var(--font)">
<option value="44100">44.1 kHz</option>
<option value="48000" selected>48 kHz</option>
<option value="96000">96 kHz</option>
<option value="192000">192 kHz</option>
</select>
</div>
<div class="setting-row"><span class="sr-label">📦 Buffer Size</span>
<select id="audioBufferSize" onchange="setAudioParams()" style="flex:1;max-width:140px;font-size:11px;padding:4px 8px;min-height:34px;border-radius:6px;border:1px solid var(--border);background:var(--surface);color:var(--text);font-family:var(--font)">
<option value="64">64</option>
<option value="128">128</option>
<option value="256" selected>256</option>
<option value="512">512</option>
<option value="1024">1024</option>
<option value="2048">2048</option>
</select>
</div>
<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>
@@ -379,7 +387,11 @@ const API = {
btMidiDisable:()=>API._fetch('/api/bluetooth/midi-disable',{method:'POST'}),
btDiscoverableSet:(on)=>API._fetch('/api/bluetooth/discoverable',{method:'POST',body:JSON.stringify({on})}),
listAudioProfiles:()=>API._fetch('/api/audio/profiles'),
setAudioProfile:(p)=>API._fetch('/api/audio/profile',{method:'POST',body:JSON.stringify({profile:p})}),
getAudioProfile:()=>API._fetch('/api/audio/profile'),
setAudioProfile:(p)=>{
if(typeof p==='string') return API._fetch('/api/audio/profile',{method:'POST',body:JSON.stringify({profile:p})});
return API._fetch('/api/audio/profile',{method:'POST',body:JSON.stringify(p)});
},
getChannelMode:()=>API._fetch('/api/channel-mode'),
setChannelMode:(m)=>API._fetch('/api/channel-mode',{method:'POST',body:JSON.stringify({channel_mode:m})}),
getRouting:(ch)=>API._fetch('/api/routing?channel='+(ch||'guitar')),
@@ -404,7 +416,6 @@ let currentChannel='guitar';
let channels=['guitar','bass','keys','vocals','backing_tracks'];
let presets=[];
let snapshots={};
let audioProfiles=[];
let currentBank=0;
let pollTimer=null;
let tunerPollTimer=null;
@@ -671,27 +682,13 @@ async function loadSystemInfo(){
}catch(e){}
}
async function loadAudioProfiles(){
async function loadAudioParams(){
try{
audioProfiles=await API.listAudioProfiles();
const grid=document.getElementById('audioProfileGrid');
const cp=audioProfiles.current||'standard';
grid.innerHTML='';
(audioProfiles.profiles||[]).forEach(p=>{
const d=document.createElement('div');
d.className='ap-card'+(p.key===cp?' active':'');
d.innerHTML='<div class="ap-key">'+p.key.replace(/_/g,' ')+'</div><div class="ap-desc">'+p.period+'fr / '+p.rate+'Hz</div>'+((p.key===cp)?'<div style="font-size:8px;color:var(--amber)">● Active</div>':'');
d.onclick=async()=>{
d.classList.add('loading');
try{
await API.setAudioProfile(p.key);
toast('Profile: '+p.key);
loadAudioProfiles();
}catch(e){toast(e.message);d.classList.remove('loading');}
};
grid.appendChild(d);
});
document.getElementById('audioProfileLabel').textContent=cp;
const p=await API.getAudioProfile();
const rate=p.rate||48000;
const period=p.period||256;
document.getElementById('audioSampleRate').value=String(rate);
document.getElementById('audioBufferSize').value=String(period);
const cm=await API.getChannelMode();
if(cm.channel_mode)document.getElementById('channelModeLabel').textContent=cm.channel_mode.replace(/-/g,' ').replace(/\b\w/g,l=>l.toUpperCase());
const rt=await API.getRouting(currentChannel);
@@ -699,6 +696,18 @@ async function loadAudioProfiles(){
}catch(e){}
}
async function setAudioParams(){
const rate=parseInt(document.getElementById('audioSampleRate').value);
const period=parseInt(document.getElementById('audioBufferSize').value);
const btn=document.querySelector('.sn-btn[data-section="audio"]');
if(btn)btn.textContent='⏳ Applying...';
try{
await API.setAudioProfile({period,rate});
toast('Audio: '+rate+'Hz / '+period+'fr');
}catch(e){toast('Failed: '+e.message);}
if(btn)btn.textContent='🎛 Audio';
}
async function loadBtStatus(){
try{
const st=await API.btStatus();
@@ -809,7 +818,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();loadAudioProfiles();loadHotspotStatus();loadBtStatus();loadBtMidi();return;}
else if(view==='settings'){openOverlay('Settings');loadNetworkInfo();loadSystemInfo();loadAudioParams();loadHotspotStatus();loadBtStatus();loadBtMidi();return;}
else if(view==='presets'){openOverlay('Presets');loadPresets();}
else if(view==='snapshots'){openOverlay('Snapshots');loadSnapshots();}
else if(view==='downloads')openOverlay('Downloads');
@@ -821,7 +830,7 @@ function init(){
openOverlay('Settings');
loadNetworkInfo();
loadSystemInfo();
loadAudioProfiles();
loadAudioParams();
loadHotspotStatus();
loadBtStatus();
loadBtMidi();
@@ -844,11 +853,11 @@ function init(){
document.getElementById('channelModeToggle').onclick=async()=>{
const cur=document.getElementById('channelModeLabel').textContent.toLowerCase();
const next=cur.includes('dual')?'stereo':'dual-mono';
try{await API.setChannelMode(next);loadAudioProfiles();toast('Mode: '+next);}catch(e){toast(e.message);}
try{await API.setChannelMode(next);loadAudioParams();toast('Mode: '+next);}catch(e){toast(e.message);}
};
document.getElementById('routingModeToggle').onclick=async()=>{
const cur=document.getElementById('routingModeLabel').textContent;
try{await API.setRouting(currentChannel,{routing_mode:cur==='MONO'?'4cm':'mono'});loadAudioProfiles();}catch(e){toast(e.message);}
try{await API.setRouting(currentChannel,{routing_mode:cur==='MONO'?'4cm':'mono'});loadAudioParams();}catch(e){toast(e.message);}
};
document.getElementById('netModeToggle').onclick=async()=>{
const lbl=document.getElementById('netDhcpStatus');
@@ -883,7 +892,7 @@ function init(){
await API.saveSettings({channel_mode:'dual-mono',brightness:8,tap_tempo:120});
await API.setRouting(currentChannel,{routing_mode:'mono'}).catch(()=>{});
toast('Defaults restored');
setTimeout(()=>{closeOverlay('Settings');loadAudioProfiles();},1000);
setTimeout(()=>{closeOverlay('Settings');loadAudioParams();},1000);
}catch(e){toast('Failed: '+e.message);}
};
document.getElementById('btnRestartSvc').onclick=()=>{toast('Restarting service...');fetch('/api/settings',{method:'POST',body:JSON.stringify({_restart:true})}).catch(()=>{});};