This is a new morse code game that Google AI built for me. Just testing to see if I can post HTML here on QRZ. If you want to try it, copy the text below and save as an .html file. Then let me know how it works for you! <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Morse Code Trainer</title> <style> body { font-family: sans-serif; text-align: center; padding: 50px; background: #f4f4f4; } #inputField { font-size: 24px; padding: 10px; width: 100px; text-align: center; text-transform: uppercase; } .status { margin-top: 20px; font-weight: bold; } </style> </head> <body> <h1>Morse Trainer</h1> <p>Listen to the code and type the character!</p> <button id="startBtn">Start / Repeat Sound</button> <br><br> <input type="text" id="inputField" autocomplete="off" autofocus placeholder="?"> <div id="status" class="status">Press "Start" to begin.</div> <script> const morseMap = { 'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.', 'G': '--.', 'H': '....', 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..', 'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.', 'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-', 'Y': '-.--', 'Z': '--..', '1': '.----', '2': '..---', '3': '...--', '4': '....-', '5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.', '0': '-----' }; let currentTarget = ""; const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); const dotDuration = 0.1; // 100ms const freq = 600; function playTone(duration, startTime) { const osc = audioCtx.createOscillator(); const gain = audioCtx.createGain(); osc.frequency.value = freq; osc.connect(gain); gain.connect(audioCtx.destination); gain.gain.setValueAtTime(0, startTime); gain.gain.linearRampToValueAtTime(1, startTime + 0.01); gain.gain.linearRampToValueAtTime(0, startTime + duration - 0.01); osc.start(startTime); osc.stop(startTime + duration); } async function playMorse(char) { const code = morseMap[char.toUpperCase()]; let time = audioCtx.currentTime + 0.1; for (const symbol of code) { const duration = symbol === '.' ? dotDuration : dotDuration * 3; playTone(duration, time); time += duration + dotDuration; } } function nextRound() { const keys = Object.keys(morseMap); currentTarget = keys[Math.floor(Math.random() * keys.length)]; playMorse(currentTarget); document.getElementById('status').innerText = "Playing new character..."; } document.getElementById('startBtn').addEventListener('click', () => { if (audioCtx.state === 'suspended') audioCtx.resume(); if (!currentTarget) nextRound(); else playMorse(currentTarget); document.getElementById('inputField').focus(); }); document.getElementById('inputField').addEventListener('input', (e) => { const input = e.target.value.toUpperCase(); if (input.length === 0) return; if (input === currentTarget) { document.getElementById('status').innerText = "Correct! Playing next..."; e.target.value = ""; setTimeout(nextRound, 800); } else { document.getElementById('status').innerText = "Incorrect. Listen again!"; e.target.value = ""; setTimeout(() => playMorse(currentTarget), 500); } }); </script> </body> </html> It worked for me. Learned something new!
pretty neat !! works here too but sounds like a ping rather than constant cw...I might play with with const gain numbers nice to see the code made a slight adjustment here to make the tone a bit more steady amplitude , will have to play more to take out clicks gain.gain.setValueAtTime(0, startTime); gain.gain.linearRampToValueAtTime(1, startTime + 0.01); gain.gain.linearRampToValueAtTime(1, startTime + duration); //- 0.01); great idea...reminds me of the old morse flash cards