diff --git a/src/web/ui-v2-dist/index.html b/src/web/ui-v2-dist/index.html index 6da216d..03be420 100644 --- a/src/web/ui-v2-dist/index.html +++ b/src/web/ui-v2-dist/index.html @@ -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
🔥 HotspotOff
Audio
-
🎛 Profile
-
+
🎛 Sample Rate + +
+
📦 Buffer Size + +
🎸 InstrumentGuitar
🔄 Channel ModeDual Mono
🔗 Routing4CM
@@ -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='
'+p.key.replace(/_/g,' ')+'
'+p.period+'fr / '+p.rate+'Hz
'+((p.key===cp)?'
● Active
':''); - 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(()=>{});};