javascripthtmlaudioevent-propagation

How do I prevent an audio file from replaying onmouseup?


I'm simulating a piano that plays a corresponding audio file when the appropriate key is clicked.

If I allow the length of the file to run as if the piano key was sustained, and if I long-press the click, it plays the file, and then it plays again when I release the mouse. It's not noticeable if I simply click. If I instruct the audio to stop and reset its currentTime attribute on release of the mouse it doesn't do this. I wondered if there was something amiss in propagation, but I couldn't seem to pinpoint it.

const keysObj = {
  'c-key': new Audio(dir + 'key08-middleC.mp3'), 
  'd-key': new Audio(dir + 'key10.mp3'), 
...
}

let keyPlay = (key) => {
  keysObj[key.target.id].play();
}

let keyReturn = (key) => {
  const isSustained = document.querySelector("input[name='sustain']:checked");

  if (!isSustained) {
    keysObj[key.target.id].pause();
  }
  
  keysObj[key.target.id].currentTime = 0;
}

let keyPress = (note) => {
  note.onmousedown = keyPlay;
  note.onmouseup = keyReturn;
}

Solution

  • So I figured it out with help from the GPT, basically I just needed to pause and reset the audio time on both mouse events to prevent the audio from replaying on mouseup when the sustain is enabled.

    As a bonus, using eventListeners instead of an 'on' property makes the file play cleanly instead of having the glitchy noise initially.

    resetAudio = (audioFile) => {
      audioFile.pause();
      audioFile.currentTime = 0;
    }
    
    let keyPlay = (key) => {
      const audio = keysObj[key.target.id];
    
      resetAudio(audio);
      audio.play();
    }
    
    let keyReturn = (key) => {
      const isSustained = document.querySelector("input[name='sustain']:checked");
      const audio = keysObj[key.target.id];
    
      if (!isSustained) {
        resetAudio(audio);
      }
    }
    
    checkClick = (clickArea, eventType) => {
        /* 
          - handles parent/child target click to prevent k/v errors if
          the label, e.g. 'F#', is clicked instead of the body of the piano key.
          - returns new MouseEvent on correct target if label is clicked. 
          - allows keyPlay and keyReturn to still work as intended 
        */
    }
    
    let keyPress = (note) => {
      note.addEventListener('mousedown', (key) => {
        keyPlay(checkClick(key, 'mousedown'));
      });
      note.addEventListener('mouseup', (key) => {
        keyReturn(checkClick(key, 'mouseup'));
      });
    }