0

I want to create a web page that plays sounds when the user presses the corresponding key on their keyboard. Different instruments/sounds are available on different tabs. The web page uses plain JavaScript created tabs. It plays different sounds on different tabs well enough as long as they use a different keyboard input. The problem arises when I try to use the same keyboard input to play different sounds in another tab. It only plays the first audio clip that was associated with that particular keyboard key no matter which tab I'm in. For instance, if I have the A key set to play a clapping sound in the first tab, and the A key set to play a dog bark sound in the second tab, it will play a clapping sound even if I'm in the second tab.

Question: I think in order to get this working I need to only grab the audio that is displayed in the current tab I'm on. How do I do that?

The needed HTML:

<div id="Drums" class="tabcontent">
  <div class="keys">
<div data-key="65" class="key">
  <kbd>A</kbd>
  <span class="sound">clap</span>
</div>
<div data-key="83" class="key">
  <kbd>S</kbd>
  <span class="sound">hihat</span>
</div>
<div data-key="68" class="key">
  <kbd>D</kbd>
  <span class="sound">ride</span>
</div>
</div>

<audio data-key="65" src="https://instaud.io/_/1YDT.wav"></audio> <!--clap-->
<audio data-key="83" src="https://instaud.io/_/1YDU.wav"></audio> <!--hihat-->
<audio data-key="72" src="https://instaud.io/_/1YDY.wav"></audio> <!--ride-->    
</div>

<div id="Animal Sounds" class="tabcontent">
  <div class="keys">
<div data-key="68" class="key">
  <kbd>D</kbd>
  <span class="sound">kick</span>
</div>
<div data-key="70" class="key">
  <kbd>F</kbd>
  <span class="sound">openhat</span>
</div>
<div data-key="71" class="key">
  <kbd>G</kbd>
  <span class="sound">boom</span>
</div>
</div>

<audio data-key="68" src="https://instaud.io/_/1YDV.wav"></audio> <!--kick-->
<audio data-key="70" src="https://instaud.io/_/1YDW.wav"></audio> <!--openhat-->
<audio data-key="71" src="https://instaud.io/_/1YDR.wav"></audio> <!--boom-->
</div>

The needed JS

function playSound (event){
  const audio = document.querySelector(`audio[data-key="${event.keyCode}"]`);
  const key = document.querySelector(`.key[data-key="${event.keyCode}"]`);
  if (!audio)return; //stops null audio
  audio.currentTime = 0;
  audio.play();
  key.classList.add('playing');

  }



function removeTransition (event) {
  if(event.propertyName !== 'transform') return; //skip if not a transform
  this.classList.remove('playing');
  }

const keys = document.querySelectorAll('.key');

keys.forEach(key => key.addEventListener('transitionend', removeTransition));

window.addEventListener('keydown', playSound);



/* End drum kit JS */


/* Start tab JS */

var i, tabcontent, tablinks;

function openCity(evt, myInstrumentName) {
//var i, tabcontent, tablinks;
// makes non-active tabs stop displaying
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
  tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablinks");
for(i = 0; i < tablinks.length; i++) {
  tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(myInstrumentName).style.display = "block";
evt.currentTarget.className += " active";
}

document.getElementById("defaultOpen").click();

If you think my thoughts on how to solve this problem are incorrect, please let me know why.

Dezmond H
  • 25
  • 7

1 Answers1

0

The problem is that querySelector is being used to grab the audio directly. First, it's necessary to make sure that the audio used is the audio from the active tab. This can be done using brackets instead of dot notation.

Instead of activeTabContent.activeTab try activeTabContent[activeTab]

More on that here.

After that, querySelector can be used to grab the audio within that specific tab.

audio = activeTabContent[activeTab].querySelector(`audio[data-key="${event.keyCode}"]`);  

This should be done for key as well.

After testing it, a strange error occurs when using a loop in the playSound function. To fix this, create another function that stores the activeTabContent in a variable:

var currentTab;
function activeTabFunc () {
   currentTab = activeTabContent[activeTab];
}

Then in the playSound function, use querySelector on the currentTab and have that equal the audio:

audio = currentTab.querySelector(`audio[data-key="${event.keyCode}"]`);  
Dezmond H
  • 25
  • 7