Build a Drum Machine - cannot pass 8th test

Tell us what’s happening:

Hi, the code works but cannot pass the 8th test. I have no clue what’s the desired method.

Failed: 8. When you press one of the keys Q, W, E, A, S, D, Z, X, C on your keyboard, the corresponding audio element should play the corresponding sound.

Your code so far

<!-- file: index.html -->
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Drum Machine</title>
    <link href="styles.css" rel="stylesheet">
  </head>
  <body>
    <div id="drum-machine">
      <div id="pad-bank">
        <button class="drum-pad" id="Heater-1">Q
          <audio class="clip" id="Q" src="https://cdn.freecodecamp.org/curriculum/drum/Heater-1.mp3">
          </audio>
        </button>
        <button class="drum-pad" id="Heater-2">W
          <audio class="clip" id="W" src="https://cdn.freecodecamp.org/curriculum/drum/Heater-2.mp3">
          </audio>
        </button>
        <button class="drum-pad" id="Heater-3">E
          <audio class="clip" id="E" src="https://cdn.freecodecamp.org/curriculum/drum/Heater-3.mp3">
          </audio>
        </button>

        <button class="drum-pad" id="Heater-4">A
          <audio class="clip" id="A" src="https://cdn.freecodecamp.org/curriculum/drum/Heater-4_1.mp3">
          </audio>
        </button>
        <button class="drum-pad" id="Clap">S
          <audio class="clip" id="S" src="https://cdn.freecodecamp.org/curriculum/drum/Heater-6.mp3">
          </audio>
        </button>
        <button class="drum-pad" id="Open-HH">D
          <audio class="clip" id="D" src="https://cdn.freecodecamp.org/curriculum/drum/Dsc_Oh.mp3">
          </audio>
        </button>

        <button class="drum-pad" id="Kick-n'-Hat">Z
          <audio class="clip" id="Z" src="https://cdn.freecodecamp.org/curriculum/drum/Kick_n_Hat.mp3">
          </audio>
        </button>
        <button class="drum-pad" id="Kick">X
          <audio class="clip" id="X" src="https://cdn.freecodecamp.org/curriculum/drum/RP4_KICK_1.mp3">
          </audio>
        </button>
        <button class="drum-pad" id="Closed-HH">C
          <audio class="clip" id="C" src="https://cdn.freecodecamp.org/curriculum/drum/Cev_H2.mp3">
          </audio>
        </button>
      </div>
      <p id="display">display</p>
    </div>

    <script src="script.js"></script>
  </body>
</html>
/* file: styles.css */
* {
  box-sizing: border-box;
}

html {
  background-color: #32012F;
}

#drum-machine {
  margin: 100px auto;
  text-align: center;
  background-color: #524C42;
  width: 400px;
  height: 500px;
  border: 2px solid #E2DFD0;
  border-radius: 10px;
}
 
#pad-bank {
  margin: 10px auto 0px;
  padding-top: 50px;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  
  width: 300px;
  height: 300px;
  gap: 10px;
}

#pad-bank button {
  background-color: #F97300;
  border: none;
  border-radius: 10px;
}

#display {
  background-color: #E2DFD0;
  width: 50%;
  padding: 10px;
  text-align: center;
  margin: 30px auto;
}

.active {
  background-color: yellow !important;
}

/* file: script.js */
/* 
const pads = document.querySelectorAll(".drum-pad");
const clips = Array.from(document.querySelectorAll(".drum-pad .clip"));

pads.forEach((pad) => {
  pad.addEventListener("click", () => {
    const audio = new Audio;
    audio.src = clips.find((clip) => pad.innerText == clip.id).src;
    audio.play();
  });
});
*/

const pads = document.querySelectorAll(".drum-pad");
const display = document.getElementById("display");

pads.forEach((pad) => {
  pad.addEventListener("click", () => {
    document.querySelector(`.drum-pad #${pad.innerText}`).play();
    display.innerText = pad.id;
    pad.classList.toggle("active")
    
    setTimeout(() => {
      pad.classList.toggle("active");
    }, 100);
    
  });
});

const body = document.querySelector("body");
const padsArr = Array.from(pads);

body.addEventListener("keydown", (e) => {
  /*
  try {
    document.querySelector(`.drum-pad #${e.key.toUpperCase()}`).play();
  }
  catch (TypeError) {
    return;
  }
  */
  const userKey = e.key.toUpperCase();
  const regex = /^[QWEASDZXC]$/;
  if (regex.test(userKey)) {
    console.log(userKey);
    padsArr.find((pad) => pad.innerText === userKey).click();
  }
  return;
});


Your browser information:

User Agent is: Mozilla/5.0 (X11; Linux x86_64; rv:139.0) Gecko/20100101 Firefox/139.0

Challenge Information:

Build a Drum Machine - Build a Drum Machine
https://www.freecodecamp.org/learn/full-stack-developer/lab-drum-machine/build-drum-machine

did you notice when you press those keys consecutively and repetitively do you hear them play corresponding sound for each of those presses?

look at this comment and in extension that thread, from a fellow camper who was facing similar problem and found a way to solve it. Build a Drum Machine - Keypress Fails (test #8) - #7 by amandappollard

happy coding :slight_smile:

2 Likes

Oh, you are right! At first I allowed multiple clips at the same time, but failing 7th test I figured that I can use .play() on the <audio>element directly and assumed this is the desired behavior.

I even thought using .play() on <audio>creates new Audio object each time. Similar to what I did in the commented out code. Those clips are so short I though they just sound like that. It’s a shame that this wasn’t mentioned in the lectures…

I did update my code:

const pads = document.querySelectorAll(".drum-pad");
const display = document.getElementById("display");

pads.forEach((pad) => {
  pad.addEventListener("click", () => {
    const audio = document.querySelector(`.drum-pad #${pad.innerText}`);
    
    if (!audio.ended) {
      audio.pause();
      audio.currentTime = 0;
    }
    
    audio.play();
    display.innerText = pad.id;
  });
});

const body = document.querySelector("body");
const padsArr = Array.from(pads);

body.addEventListener("keypress", (e) => {
  const userKey = e.key.toUpperCase();
  const regex = /^[QWEASDZXC]$/;
  if (regex.test(userKey)) {
    console.log(userKey);
    padsArr.find((pad) => pad.innerText === userKey).click();
  }
  return;
});

However, it still fails the test. Do you think I should declare each pad like the guy from the thread you linked? Is it a better approach? Like more resource efficient or something? I can imagine constantly searching for id can be resource hungry, but I wouldn’t like to map all keyboard by hand.

Thank you a lot for your help :>>

It seems like I can’t edit the message above.

I have this code pasted into codepen, this might help to debug it if somebody is willing to help, so I wanted to share it:

https://codepen.io/snafix/pen/jEWEaqM

1 Like

im saying there is a clue to this problem not how he implemented it, your implementation is much cleaner, good job :clap:

  • try exploring this

  • why didnt you go with direct “play()” method on audio element directly from here as well? as you did with “drum pads”

  • also as both of these (event listeners) are using same play method why not create a simple function and call it from both of those two place that way it becomes more readable and less error prone.

happy coding :slight_smile:

1 Like

At first I used different querySelectors for those events, but now they are the same. Code will be cleaner that way, thanks.

I tried to trigger the <audio> element directly, but it didn’t pass the test as well. I sticked to triggering the parent element, because of the wording of 7th step:

When you press the trigger key associated with each .drum-pad, the audio clip contained in its child audio element should be triggered (e.g. pressing the Q key should trigger the drum pad which contains the string Q, pressing the W key should trigger the drum pad which contains the string W, etc.).

I updated my code according to your guidelines:

const pads = document.querySelectorAll(".drum-pad");
const display = document.getElementById("display");
const body = document.querySelector("body");
const padsArr = Array.from(pads);
const clipsArr = Array.from(document.querySelectorAll(".clip"));

pads.forEach((pad) => {
  pad.addEventListener("click", () => {
    firePad(pad);
  });
});

body.addEventListener("keypress", (e) => {
  const userKey = e.key.toUpperCase();
  const regex = /^[QWEASDZXC]$/;
  if (regex.test(userKey)) {
    firePad(padsArr.find((pad) => pad.innerText === userKey));
  }
  return;
});

function firePad(pad) {
  const audio = clipsArr.find((clip) => clip.id === pad.innerText);

  if (!audio.ended) {
    audio.pause();
    audio.currentTime = 0;
  }

  audio.play();
  display.innerText = pad.id;
}

https://codepen.io/snafix/pen/jEWEaqM

Sadly, I still can’t pass the 8th test. But I really think my project works as desired, this feels rough.

Thank you very much for your feedback and support :slight_smile:

  • yeah been there, this also seems quite strange to me, it seems to be doing whats been asked for. lets keep troubleshooting.

btw there is more you can do interms of code cleanup there

  • you dont really need “padsArr”, your firePad method only needs “KEY”

happy coding :slight_smile:

Oh yeah! This is a waste from calling .click() on the pad element.

Thank you for your help :)).

I will try to open github issue regarding this lab when I have some free time.

1 Like