let ws = null; let audioCtx = null; let gainNode = null; // Il controller del volume let nextStartTime = 0; const connectBtn = document.getElementById('connectBtn'); const tgInput = document.getElementById('tgInput'); const setTgBtn = document.getElementById('setTgBtn'); const displayScreen = document.getElementById('displayScreen'); const statusText = document.getElementById('statusText'); // --- CONTROLLI VOLUME --- const volumeSlider = document.getElementById('volumeSlider'); const volumeValue = document.getElementById('volumeValue'); volumeSlider.addEventListener('input', (e) => { const val = parseFloat(e.target.value); volumeValue.innerText = Math.round(val * 100) + '%'; // Modifica il volume in tempo reale if (gainNode) { gainNode.gain.value = val; } }); // --- RIPRODUZIONE AUDIO PCM --- function playPCM320(arrayBuffer) { if (!audioCtx || !gainNode) return; const int16Array = new Int16Array(arrayBuffer); const float32Array = new Float32Array(int16Array.length); for (let i = 0; i < int16Array.length; i++) { float32Array[i] = int16Array[i] / 32768.0; } const buffer = audioCtx.createBuffer(1, float32Array.length, 8000); buffer.getChannelData(0).set(float32Array); const source = audioCtx.createBufferSource(); source.buffer = buffer; // Colleghiamo l'audio al controller del volume invece che direttamente all'uscita source.connect(gainNode); const currentTime = audioCtx.currentTime; if (nextStartTime < currentTime) { nextStartTime = currentTime + 0.02; } source.start(nextStartTime); nextStartTime += buffer.duration; } // --- CONNESSIONE WEBSOCKET --- function startAudio() { if (!audioCtx) { audioCtx = new (window.AudioContext || window.webkitAudioContext)(); // Creazione del nodo Volume gainNode = audioCtx.createGain(); gainNode.connect(audioCtx.destination); gainNode.gain.value = parseFloat(volumeSlider.value); } if (audioCtx.state === 'suspended') { audioCtx.resume(); } const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; ws = new WebSocket(`${protocol}//${window.location.host}/ws`); ws.binaryType = 'arraybuffer'; ws.onopen = () => { connectBtn.style.display = 'none'; inviaCambioTG(tgInput.value); }; ws.onmessage = (event) => { if (event.data instanceof ArrayBuffer) { playPCM320(event.data); } else if (typeof event.data === 'string') { const data = JSON.parse(event.data); // --- GESTIONE ERRORE SERVER PIENO --- if (data.action === "error") { displayScreen.innerText = "SERVER PIENO"; displayScreen.style.background = "#e74c3c"; // Rosso[cite: 5] statusText.innerText = "❌ " + data.text; statusText.style.color = "#e74c3c"; return; } if (data.action === "display") { displayScreen.innerText = data.text; statusText.style.color = "#bdc3c7"; // Ripristina il colore di default del testo[cite: 5] if (data.active) { displayScreen.style.background = "#e67e22"; // Arancione durante RX[cite: 5] } else { displayScreen.style.background = "#1abc9c"; // Verde in Standby[cite: 5] } } } }; ws.onclose = () => { // Se il display non è in stato di errore "SERVER PIENO", mostra la riconnessione standard[cite: 5] if (displayScreen.innerText !== "SERVER PIENO") { statusText.innerText = "Connessione persa. Riconnessione..."; statusText.style.color = "#bdc3c7"; connectBtn.style.display = 'block'; connectBtn.innerText = "Riconnetti Ricevitore"; } }; } // --- FUNZIONE PER CAMBIARE TG --- function inviaCambioTG(nuovoTG) { if (!nuovoTG || nuovoTG <= 0) return; if (ws && ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ action: "cambia_tg", tg: nuovoTG })); displayScreen.innerText = "SINTONIA..."; statusText.innerText = "Sintonizzato su TG " + nuovoTG; } else { statusText.innerText = "Pronto a sintonizzare TG " + nuovoTG; } } // Scelta Rapida dai tasti prefissati function setQuickTg(valore) { tgInput.value = valore; inviaCambioTG(valore); } // --- EVENTI --- connectBtn.addEventListener('click', startAudio); setTgBtn.addEventListener('click', () => inviaCambioTG(tgInput.value)); // Invio anche premendo "Invio" sulla tastiera dentro la casella di testo tgInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { inviaCambioTG(tgInput.value); } });