// jshint asi:true var short = 80 var long = 200 var audioFreq = 660 var audioFreqMe = audioFreq * 6 / 5 // I think this works out to a minor third var ac = new AudioContext() var mygain = ac.createGain() mygain.connect(ac.destination) mygain.gain.value = 0 var myosc = ac.createOscillator() myosc.connect(mygain) myosc.frequency.value = audioFreqMe myosc.start() var theirgain = ac.createGain() theirgain.connect(ac.destination) theirgain.gain.value = 0 var theirosc = ac.createOscillator() theirosc.connect(theirgain) theirosc.frequency.value = audioFreq theirosc.start() var repeatInterval function message(event) { let now = ac.currentTime let duration = Number(event.data) || 0 duration = Math.min(duration, long) if (now === 0) { // Audio Context hasn't started, we can't make sound yet return } theirgain.gain.linearRampToValueAtTime(0.1, now + 0.01) mygain.gain.setValueAtTime(0.1, now + duration/1000) theirgain.gain.linearRampToValueAtTime(0.0, now + 0.01 + duration/1000) } function send(duration) { let now = ac.currentTime window.socket.send(duration) if (now === 0) { return } mygain.gain.linearRampToValueAtTime(0.1, now + 0.01) mygain.gain.setValueAtTime(0.1, now + duration/1000) mygain.gain.linearRampToValueAtTime(0.0, now + 0.01 + duration/1000) } function key(event) { let duration = 0 ac.resume() if (event.repeat) { // Ignore key repeats generated by the OS, we do this ourselves return } if ((event.button === 0) || (event.code == "Period") || (event.key == "Shift")) { duration = short } if ((event.button === 2) || (event.code == "Slash") || (event.code == "KeyZ")) { duration = long } if (duration === 0) { return } if (repeatInterval) { clearInterval(repeatInterval) } if (event.type.endsWith("down")) { send(duration) repeatInterval = setInterval(() => {send(duration)}, duration + short) } } function canWeJustNot(event) { event.preventDefault() return false } function init() { let wsUrl = new URL(window.location) wsUrl.protocol = "ws:" wsUrl.pathname += "chat" window.socket = new WebSocket(wsUrl) window.socket.addEventListener("message", message) // disable RMB context menu document.addEventListener("contextmenu", e => canWeJustNot(e)) document.addEventListener("mousedown", e => key(e)) document.addEventListener("mouseup", e => key(e)) document.addEventListener("keydown", e => key(e)) document.addEventListener("keyup", e => key(e)) } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", init) } else { init() }