Indicador Mark / Space HTML

 Segue uma abordagem visual do Tuning Scope de tubo (conhecido como Cross-line Indicator)!



Estão sintonizados 2125Hz e 2295Hz

Site com áudio RTTY : http://internet-tty.net:8000/ITTY


Segue o código!

<!DOCTYPE html>
<html lang="pt-br">
<head>
    <meta charset="UTF-8">
    <title>RTTY Tuning Scope - CRT Style</title>
    <style>
        body { background: #1a1a1a; color: #00ff00; font-family: 'Courier New', monospace; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; margin: 0; }
        .container { border: 4px solid #333; border-radius: 50%; padding: 20px; background: #000; box-shadow: 0 0 50px #004400; position: relative; }
        canvas { background: #001100; border-radius: 50%; border: 2px solid #003300; width: 400px; height: 400px; }
        .controls { margin-top: 20px; text-align: center; display: flex; flex-direction: column; gap: 10px; align-items: center; }
        button { background: #004400; color: #00ff00; border: 1px solid #00ff00; padding: 10px 20px; cursor: pointer; font-size: 16px; transition: 0.3s; font-weight: bold; }
        button:hover { background: #00ff00; color: #000; }
        .info { font-size: 12px; color: #008800; }
        input[type=range] { width: 250px; accent-color: #00ff00; cursor: pointer; }
        label { font-size: 14px; }
    </style>
</head>
<body>

    <h2>RTTY X-Y SCOPE</h2>

    <div class="container">
        <canvas id="scope" width="400" height="400"></canvas>
    </div>

    <div class="controls">
        <button id="startBtn">ATIVAR SENSOR/ÁUDIO</button>
        
        <div style="display: flex; align-items: center; gap: 10px;">
            <label>SENSIVEL.</label>
            <input type="range" id="gainSlider" min="1" max="50" step="1" value="15">
        </div>

        <div class="info">Sintonize em: Mark 2125Hz (V) | Space 2295Hz (H)</div>
    </div>

    <script>
        let audioCtx, analyserMark, analyserSpace, source, gainNode;
        const canvas = document.getElementById('scope');
        const ctx = canvas.getContext('2d');
        const gainSlider = document.getElementById('gainSlider');

        async function initAudio() {
            audioCtx = new (window.AudioContext || window.webkitAudioContext)();
            
            try {
                // DESATIVAR AGC e Noise Suppression para o sinal não sumir
                const stream = await navigator.mediaDevices.getUserMedia({ 
                    audio: {
                        echoCancellation: false,
                        noiseSuppression: false,
                        autoGainControl: false
                    } 
                });
                
                source = audioCtx.createMediaStreamSource(stream);

                // Criar o amplificador (Gain Node)
                gainNode = audioCtx.createGain();
                gainNode.gain.value = gainSlider.value;

                // Filtro para Mark (2125 Hz)
                const filterMark = audioCtx.createBiquadFilter();
                filterMark.type = "bandpass";
                filterMark.frequency.value = 2125;
                filterMark.Q.value = 25;

                // Filtro para Space (2295 Hz)
                const filterSpace = audioCtx.createBiquadFilter();
                filterSpace.type = "bandpass";
                filterSpace.frequency.value = 2295;
                filterSpace.Q.value = 25;

                analyserMark = audioCtx.createAnalyser();
                analyserSpace = audioCtx.createAnalyser();
                analyserMark.fftSize = 1024;
                analyserSpace.fftSize = 1024;

                // Fluxo: Microfone -> Ganho -> Filtros -> Analisadores
                source.connect(gainNode);
                gainNode.connect(filterMark);
                filterMark.connect(analyserMark);
                gainNode.connect(filterSpace);
                filterSpace.connect(analyserSpace);

                draw();
                document.getElementById('startBtn').innerText = "INDICADOR ATIVO";
            } catch (err) {
                alert("Erro ao acessar microfone: " + err);
            }
        }

        function draw() {
            requestAnimationFrame(draw);

            const dataMark = new Uint8Array(analyserMark.frequencyBinCount);
            const dataSpace = new Uint8Array(analyserSpace.frequencyBinCount);
            analyserMark.getByteTimeDomainData(dataMark);
            analyserSpace.getByteTimeDomainData(dataSpace);

            // Limpeza rápida para manter o traço nítido
            ctx.fillStyle = "rgba(0, 10, 0, 0.4)";
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            // Desenhar a grade (retículo)
            ctx.strokeStyle = "rgba(0, 50, 0, 0.5)";
            ctx.beginPath();
            ctx.moveTo(200, 0); ctx.lineTo(200, 400);
            ctx.moveTo(0, 200); ctx.lineTo(400, 200);
            ctx.stroke();

            // Desenhar o traço X-Y
            ctx.beginPath();
            ctx.strokeStyle = "#44ff88";
            ctx.lineWidth = 2.5;
            ctx.shadowBlur = 10;
            ctx.shadowColor = "#44ff88";

            // Multiplicador visual para expandir o desenho
            const zoom = 1.4;

            for (let i = 0; i < dataMark.length; i += 2) {
                // Normaliza de 0-255 para -1 a 1, e escala para o tamanho do canvas (200px de raio)
                let yNorm = (dataMark[i] - 128) / 128;
                let xNorm = (dataSpace[i] - 128) / 128;

                let y = 200 + (yNorm * 200 * zoom);
                let x = 200 + (xNorm * 200 * zoom);

                if (i === 0) ctx.moveTo(x, y);
                else ctx.lineTo(x, y);
            }
            ctx.stroke();
        }

        // Atualiza o ganho quando você move o slider
        gainSlider.oninput = () => {
            if (gainNode) gainNode.gain.value = gainSlider.value;
        };

        document.getElementById('startBtn').addEventListener('click', () => {
            if (!audioCtx) initAudio();
            else if (audioCtx.state === 'suspended') audioCtx.resume();
        });
    </script>
</body>
</html>


Comentários

Postagens mais visitadas deste blog

JVC Compulink, COMPU LINK, JVC, Tape Deck, Arduino, DCS Codes

JVC Compu Link Final

RTTY, PSK31, FT8, JS8CALL, NBTV, RDS FM, OLIVIA, SSTV, SSTV AUTO,CW, ASCII Encoder / Decoder