Search code examples
javascriptaudiodom-eventsmouseeventkeyevent

How to use event.code and event.button in if, else condition properly?


my goal is to build playing drums using vanilla Javascript, whole code worked perfectly when I was using only the keydown event, unfortunately, my drums have to play also on mouse 'click'. When I added "|| event.button == aKey == 0" this part to my condition, it still plays, but only one sound on each key. So I assumed that there is something wrong with my condition.

And also if it would be possible to somehow make my code less repeatable, I would appreciate it.

const aKey = document.getElementById("A-key");
const sKey = document.getElementById("S-key");
const dKey = document.getElementById("D-key");
const fKey = document.getElementById("F-key");
const gKey = document.getElementById("G-key");
const hKey = document.getElementById("H-key");
const jKey = document.getElementById("J-key");
const kKey = document.getElementById("K-key");
const lKey = document.getElementById("L-key");

const playFunction = (event) => {
    if (event.code == "KeyA" || event.button == aKey == 0) {
        // 
        let audioA = document.createElement("AUDIO");
        if (audioA.canPlayType("audio/wav")) {
            audioA.setAttribute("src","sounds/boom.wav");
        }
        audioA.setAttribute("autoplay", "autoplay");
        document.body.appendChild(audioA);

    } else if (event.code == "KeyS" || event.button == sKey == 0 ) {

        let audioS= document.createElement("AUDIO");
        if (audioS.canPlayType("audio/wav")) {
            audioS.setAttribute("src","sounds/clap.wav");
        }
        audioS.setAttribute("autoplay", "autoplay");
        document.body.appendChild(audioS);

    } else if (event.code == "KeyD" || event.button == dKey == 0) {

        let audioD = document.createElement("AUDIO");
        if (audioD.canPlayType("audio/wav")) {
            audioD.setAttribute("src","sounds/hihat.wav");
        }
        audioD.setAttribute("autoplay", "autoplay");
        document.body.appendChild(audioD);

    } else if (event.code == "KeyF"  || event.button == fKey == 0) {
        let audioF = document.createElement("AUDIO");
        if (audioF.canPlayType("audio/wav")) {
            audioF.setAttribute("src","sounds/kick.wav");
        }
        audioF.setAttribute("autoplay", "autoplay");
        document.body.appendChild(audioF);

    } else if (event.code == "KeyG" || event.button == gKey == 0) {
        let audioG = document.createElement("AUDIO");
        if (audioG.canPlayType("audio/wav")) {
            audioG.setAttribute("src","sounds/openhat.wav");
        }
        audioG.setAttribute("autoplay", "autoplay");
        document.body.appendChild(audioG);

    } else if (event.code == "KeyH" || event.button == hKey == 0) {
        let audioH = document.createElement("AUDIO");
        if (audioH.canPlayType("audio/wav")) {
            audioH.setAttribute("src","sounds/ride.wav");
        }
        audioH.setAttribute("autoplay", "autoplay");
        document.body.appendChild(audioH);

    } else if (event.code == "KeyJ" || event.button == jKey == 0) {
        let audioJ = document.createElement("AUDIO");
        if (audioJ.canPlayType("audio/wav")) {
            audioJ.setAttribute("src","sounds/snare.wav");
        }
        audioJ.setAttribute("autoplay", "autoplay");
        document.body.appendChild(audioJ);

    } else if (event.code == "KeyK" || event.button == kKey == 0) {
        let audioK = document.createElement("AUDIO");
        if (audioK.canPlayType("audio/wav")) {
            audioK.setAttribute("src","sounds/tink.wav");
        }
        audioK.setAttribute("autoplay", "autoplay");
        document.body.appendChild(audioK);

    } else if (event.code == "KeyL" || event.button == lKey == 0) {
        let audioL = document.createElement("AUDIO");
        if (audioL.canPlayType("audio/wav")) {
            audioL.setAttribute("src","sounds/tom.wav");
        }
        audioL.setAttribute("autoplay", "autoplay");
        document.body.appendChild(audioL);
    } else {
        console.log("Try to use specified keys.")
    }
};

window.addEventListener('keydown', playFunction, false);
window.addEventListener('click', playFunction, false);

Solution

  • event.button == kKey == 0 doesn't make much sense. This evaluates like (foo == bar) == baz, that is, the first condition is tested, then the result of that (true or false) is checked against the other condition. If you want to test multiple conditions, use || or && between every condition. Also, always use === to avoid surprising conversion behavior.

    As for the refactor request, whenever you have a bunch of branches that only differ based on parameterizable values, like the button text or the sound, use a data structure such as an array or object and index/key into it.

    Specifically, all you need here are key -> audio or audio URL pairs, so an object seems suitable.

    Once you have such a structure, then you can access the power of loops to DRY out your code.

    I don't have your audio files or markup, so you can try to adapt this proof of concept to your project:

    const baseURL = `https://upload.wikimedia.org/wikipedia/commons/`;
    const sounds = {
      a: `7/7c/Bombo_Leg%C3%BCero_Grave.ogg`,
      s: `7/7f/Bombo_Ac%C3%BAstico.ogg`,
      d: `3/35/Bongo_Agudo.ogg`,
      f: `4/44/Bongo_Grave.ogg`,
      g: `b/b4/Sting.ogg`,
      // ... add more key-sound URL pairs ...
    };
    
    Object.keys(sounds).forEach(key => {
      const btn = document.createElement("button");
      document.querySelector("#drum-pad").appendChild(btn);
      const sound = new Audio(baseURL + sounds[key]);
      sounds[key] = sound;
      btn.textContent = key;
      btn.addEventListener("click", e => {
        sound.currentTime = 0;
        sound.play();
      });
    });
    
    document.addEventListener("keydown", e => {
      if (sounds[e.key]) {
        sounds[e.key].currentTime = 0;
        sounds[e.key].play();
      }
    });
    <div id="drum-pad"></div>