0

totally beginner-question right here. Started studying front-end dev a month ago and now that i've reached Javascript, got working on my first practice projects. In this case, I want to create this really simple guitar tuner where you click a button and it executes its correspondent string.

This below is what i got so far, but can't express how to get the id of the button clicked. And also, can't figure out how to end one note's loop when clicking on another button.

const keyS = document.addEventListener('keydown', function(e){
    (e.key === 'd') ? this.getElementById ("string6").play()
   :(e.key === 'f') ? this.getElementById ("string5").play()
   :(e.key === 'g') ? this.getElementById ("string4").play()
   :(e.key === 'j') ? this.getElementById ("string3").play()
   :(e.key === 'k') ? this.getElementById ("string2").play()
   :(e.key === 'l') ? this.getElementById ("string1").play()
   : alert("That's not a valid key!")
})
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles/main.css">
    <title>Guitar Tuner</title>
    <script src="scripts/main.js"></script>
</head>
<body>
    <ul>
        <li><audio id="string" src="sounds/string6.mp3" type="audio/mpeg" controls loop></audio></li>
        <li><audio id="string5" src="sounds/string5.mp3" type="audio/mpeg" controls loop></audio></li>
        <li><audio id="string4" src="sounds/string4.mp3" type="audio/mpeg" controls loop></audio></li>
        <li><audio id="string3" src="sounds/string3.mp3" type="audio/mpeg" controls loop></audio></li>
        <li><audio id="string2" src="sounds/string2.mp3" type="audio/mpeg" controls loop></audio></li>
       <li><audio id="string1" src="sounds/string1.mp3" type="audio/mpeg" controls loop></audio></li>
       <br>
        <button onclick="clickNote()">6th String</button>
        <button onclick="clickNote()">5th String</button>
        <button onclick="clickNote()">4th String</button>
        <button onclick="clickNote()">3rd String</button>
        <button onclick="clickNote()">2nd String</button>
        <button onclick="clickNote()">1st String</button>
  </ul>

</body>
</html>

I know probably is a really dumb question, but I want to understand how this works properly to then start fiddling with it.

Thank you all in advance, and any JS learning or front-end career developing tips are very much welcome!

P.S: May you forgive any gramatical errors, for english is not my mother's tongue.

  • You need when button clicked sound play right ? And if i clicked d f j g k l button clicked sound play – AbdElzaher May 25 '21 at 05:22
  • For how to get the id of the clicked element - https://stackoverflow.com/q/30786154/853295 – garethb May 25 '21 at 05:26
  • It may be simpler to have a single audio element and play all the sounds using that one. You can set its source based on the button pressed. Stopping it is easy as you can just play the next sound and it will stop the previous one. – Paul Rooney May 25 '21 at 05:29
  • You can also pass an argument to your `clickNote()` function. It could be the note e.g. `clickNote("a")` or the index e.g. `clickNote(1)`. In your html just call the function with the required argument e.g. ` – Paul Rooney May 25 '21 at 05:33
  • [How to get the id of the clicked button](https://stackoverflow.com/questions/4825295/onclick-to-get-the-id-of-the-clicked-button). From your code though it looks like you are using key presses - [here's how to detect which key was pressed](https://stackoverflow.com/questions/1846599/how-to-find-out-what-character-key-is-pressed). – Don't Panic May 25 '21 at 05:52

2 Answers2

1

Short General Answer:

You can get the element + attributes by using this like:

function doit(obj) {
  alert(obj.id)
}
<button id="me" onclick="doit(this)">test of ME</button>

Or if it is focus-able like this:

function doit() {
  var obj=document.activeElement;
  alert(obj.id);
}
<button id="me" onclick="doit()">test of ME</button>

Or if you use EventListener just like this:

document.getElementById('me').addEventListener('click',doit);

function doit() {
  alert(this.id);
}
<button id="me">test of ME</button>

Your exact answer + idea:

It is better we use an attribute to detect which key it is, to we can use a general function for all. like this:

// For being sure that all elements load, we have to set EventListeners when DOMContentLoaded:
window.addEventListener('DOMContentLoaded', function(e) {
    
    document.querySelectorAll('button[note]') // Get all buttons that have note as attributes
    
      .forEach(function(obj){  // For each of them
      
        obj.addEventListener('click',playnote); // Set playnote function for on click
        
      });
    
    
});

// Also the general keydown event listener:
window.addEventListener('keydown',playnote);

// Where we decied to play the note:
function playnote(e) { // e will be Event

  var note; // Defining note variable for local use
  
  if (e.type=='click') { // Checking the event is clicking on button
  
    note=this.getAttribute('note'); // Getting the note attribute
    
  } else { // Or else is a keydown
  
    note=e.key; // Getting the key
    
  }
  
  console.log(note); // Just debugging what note it got (You have to remove it later)
  
  note=document.querySelector('audio[note="'+note+'"]'); // Find the audio element by it "note" attribute
  
  if (note) note.play(); // Play if the element exist
  
}
<audio note="a" src="sounds/a.mp3" type="audio/mpeg" controls></audio><br>
<audio note="b" src="sounds/b.mp3" type="audio/mpeg" controls></audio><br>
<audio note="c" src="sounds/c.mp3" type="audio/mpeg" controls></audio><br>
<br>
<button note="a">A</button><br>
<button note="b">B</button><br>
<button note="c">C</button><br>

Note (1): If you don't need the audio element be seen, you have to change the playnote function and create an audio element instantly instead.

Note (2): Audio elements sometimes have delay to play if the source be a file. So if you need fast play i recommend you use Data URI as source.

About the loop that you asked: https://www.w3schools.com/html/html5_audio.asp https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/loop

MMMahdy-PAPION
  • 915
  • 10
  • 15
0

As Paul mentioned in his comments, use one audio control, and then have your buttons update that. This example uses data attributes on each button to identify the string, and also wraps the buttons in a container and uses event delegation to capture button events as they bubble up the DOM so you don't have a listener on each button.

// Caching the audio and container elements
const audio = document.querySelector('audio');
const buttons = document.querySelector('#buttons');

// Adding an event listener to the button container only
buttons.addEventListener('click', handleClick, false);

function handleClick(e) {

   // Grab the id from the data attribute
  const { target: { dataset: { id } } } = e;

  // There is not .stop() method, so we need to pause
  // the audio, and then reset the timer
  audio.pause();
  audio.currentTime = 0;

  console.log(`Play ${id} string`);

  // An example
  audio.src = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/Yodel_Sound_Effect.mp3';

  // Your code will look like this
  // audio.src = `sounds/string${id}.mp3`;
  audio.play();
}
<audio type="audio/mp3" controls loop /></audio>
<div id="buttons">
  <button data-id="6">6th String</button>
  <button data-id="5">5th String</button>
  <button data-id="4">4th String</button>
  <button data-id="3">3rd String</button>
  <button data-id="2">2nd String</button>
  <button data-id="1">1st String</button>
</div>

Additional documentation

Andy
  • 61,948
  • 13
  • 68
  • 95