Difficulty getting audio to play in drum-machine

No, using src is not the answer. How do I know? Because I have your drum machine working locally here on my computer :slight_smile:

Look in App.js, where you are creating each DrumPad. What are the names of the attributes you are passing to the DrumpPad? Those are the prop names you need to use in DrumPad.js. There is no value for this.props.name in DrumPad.js because you aren’t passing an attribute with the name name when you create the DrumPad in App.js.

1 Like

When I use attributes like id or letter I run into the same error:

TypeError: Cannot read property 'play' of null

DrumPad.handleClick

   7 | 
   8 |   handleClick = () => {
   9 |   const sound = document.querySelector(`#${this.props.id}`)
> 10 |   sound.play()
  11 | }
  12 | 
  13 |   render() {

I’m wondering if there’s something that I’m missing completely? Do I need to change some of my attributes in App.js or in DrumPad.js?

1 Like

I think you might be :slight_smile: Look at the <audio> tag you are creating in DrumPad.js. Are you setting the id attribute correctly?

1 Like

I’m not sure what you mean. How would I go about setting the id attribute for audio differently?

1 Like

Here is your current code:

<audio
          className='clip'
          src={this.props.src}
          id = {this.props.name}
          type='audio/mp3'>
</audio>

Look at what you are setting the id attribute with. I’m pretty sure we just came to the realization that this.props.name doesn’t exist in DrumpPad.js. Remember, you can only use props names that you pass into DrumpPad when creating the DrumPads in App.js.

1 Like

Okay, that makes sense. My audio element is now:

          className='clip'
          src={this.props.src}
          id = {this.props.id}
          type='audio/mp3'
          >
        </audio>

This passes 4 out of 8 tests but throws the following error:

TypeError: sound.play is not a function
DrumPad.handleClick
src/DrumPad.js:10
   7 | 
   8 |   handleClick = () => {
   9 |   const sound = document.querySelector(`#${this.props.id}`)
> 10 |   sound.play()
  11 | }
  12 | 
  13 |   render() {
1 Like

Are you able to click on your drum pads now and get a sound? From what you have pasted above it seems like you should be able to, but if not then you’ll have to update github with your current code so I can see everything.

I will tell you though that right now one of your drum pads will not work and will throw an error when clicked on. I’m not going to tell you which one but I will give you a hint: id’s cannot have spaces in them.

1 Like

I updated that specific id so that there is no space in it now. To answer your question, no I’m not able to click on my drum-pads and get a sound.

Here is my updated repo:

1 Like

Ahh, so now you’ve got an HTML issue, not a JS issue. HTML element id’s must be unique. The <div> that wraps the <audio> can’t have the same id as the <audio>. The fix is in the JS (since you are creating the elements there), but it’s not really a JS issue, it’s just invalid HTML.

I think once you fix this you should start hearing sounds. Have fun.

1 Like

Continuing this thread:

I’ve passed all of my tests except for the final one. I need text to show up in my display to indicate which drum-pad is triggered. I have a display component (in Display.js) as well as a message variable set to ‘no sound’. However, I’m not sure how to go about setting the name attribute from Sounds to be triggered in the display. Is this something that can be linked to the DrumPad component? Currently, I have code to update the message variable that looks like this:

render(){
    let message = 'No sound';
    /*if (DrumPad.play()) {
      message = `Sound: ${Sounds.name.key}`;
    }*/
  return (

However, I’ve commented this code out because DrumPad.play() threw an error.

Any help is greatly appreciated. Here is my repo with updated code:

1 Like

Remember how you originally had a playSound method in App.js, and you passed that method to DrumPad, and then DrumPad would call the App.playSound method when the user clicked a button? The advantage of doing it that way is that App would know which button is clicked, which would then allow it to get that information to Display. The way you have it working right now is that DrumPad knows the button is clicked, and it plays the sounds itself, and that’s it, it doesn’t communicate with App about which button was clicked. So there is no way for App to tell Display which button is clicked :frowning:

1 Like

I’ve completed the drum-machine project. My solution to the above problem is the following:

constructor(props){
    super(props)
    this.state = {
      message: 'No sound'
    }
  }
  setMessage = (message) => this.setState({message});

I then linked setMessage to DrumPad.js and this.state.message to Display.js.

  Sounds.map(s => (
      <DrumPad
        id = {s.name}
        letter={s.key}
        src={s.source}
        setMessage={this.setMessage}

        />
    ))}
<Display currentSoundText={this.state.message} />

Here is my updated repo:

Congrats on getting it working. A few things:

  • I think you want the sound name to show in the display when you press a key on the keyboard, right?
  • The way you are adding the keydown handler is creating multiple unnecessary handlers. If you know how to look at the event listeners in the dev tools you’ll see that you have added 9 keydown event handlers that all do the same thing because a keydown handler is added for every DrumPad you are creating. I think you need to add that handler once in App instead.
  • Speaking of the keydown handler, try hitting the space bar. You’ll want to make sure that you have a valid DrumPad key before you call querySelector. Or you could use a try/catch to ignore the exception that occurs when it is not.
1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.