skip to Main Content

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;
}

2

Answers


  1. Chosen as BEST ANSWER

    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'));
      });
    }
    

  2. But why are you playing sound files of single keys for a piano simulator when you can easily generate sounds in JavaScript? 🙂

    Here’s a little sound generating utility to play with, and from which you can pinch the sound making function and do things right.

    <!DOCTYPE html>
    <head>
    
    <style type="text/css">
    
    input[type="range"]{vertical-align:middle; width:300px; cursor:pointer;}
    
    button{cursor:pointer; float:left;}
    
    .InfoTable{width:auto; overflow:hidden; table-layout:fixed; border-collapse:collapse; text-align:right; font:normal 400 13px Arial;}
    .InfoTable td{padding:2px 5px; border:1px solid #d0d0d0; white-space:nowrap;}
    
    .InfoTable td:nth-child(1){width:100px;}
    .InfoTable td:nth-child(2){width:70px;}
    .InfoTable td:nth-child(3){width:auto; text-align:center;}
    
    </style>
    </head>
    
    <body>
    
    <script type="text/javascript">
    
    var ClassicAudioContext=new AudioContext;
    
    function Beep(vol,freq,duration,wave){
     const oscillator=ClassicAudioContext.createOscillator();
     const gain=ClassicAudioContext.createGain();
     oscillator.connect(gain);
     oscillator.frequency.value=freq;
     oscillator.type=wave;
     gain.connect(ClassicAudioContext.destination);
     gain.gain.value=vol*0.01;
     oscillator.start(ClassicAudioContext.currentTime);
     oscillator.stop(ClassicAudioContext.currentTime+(duration*0.001));
    }
    
    </script>
    <table class="InfoTable">
    
    <tr><td><button onclick='Beep(vIn.value,fIn.value,dIn.value,tIn.value);'>Play</button> Wave</td><td><span id="tOut">sine</span></td><td> <input type="range" oninput="tOut.innerHTML=['sine','square','sawtooth','triangle'][Number(this.value)];" id="tIn" value="0" min="0" max="3"></td></tr>
    
    <tr><td>Volume</td><td><span id="vOut">0</span></td><td>   <input type="range" oninput="vOut.innerHTML=this.value;" id="vIn" value="5" min="0" max="100"></td></tr>
    
    <tr><td>Duration</td><td><span id="dOut">1 ms</span></td><td> <input type="range" oninput="dOut.innerHTML=this.value+' ms';" id="dIn" value="100" min="1" max="1000"></td></tr>
    
    <tr><td>Frequency</td><td><span id="fOut">40 Hz</span></td><td>   <input type="range" oninput="fOut.innerHTML=this.value+' Hz';" id="fIn" value="250" min="40" max="5000"></td></tr>
    
    <table>
    
    </body>
    </html>
    

    NB: If you need help with notes to frequencies for your simulator, use the arrays below…

    const KeyName=['C8 Eighth octave','B7','A♯7/B♭7','A7','G♯7/A♭7','G7','F♯7/G♭7','F7','E7','D♯7/E♭7','D7','C♯7/D♭7','C7 Double high C','B6','A♯6/B♭6','A6','G♯6/A♭6','G6','F♯6/G♭6','F6','E6',
    'D♯6/E♭6','D6','C♯6/D♭6','C6 Soprano high C','B5','A♯5/B♭5','A5','G♯5/A♭5','G5','F♯5/G♭5','F5','E5','D♯5/E♭5','D5','C♯5/D♭5','C5 Tenor C','B4','A♯4/B♭4','A4 A440','G♯4/A♭4','G4','F♯4/G♭4',
    'F4','E4','D♯4/E♭4','D4','C♯4/D♭4','C4 Middle C','B3','A♯3/B♭3','A3','G♯3/A♭3','G3','F♯3/G♭3','F3','E3','D♯3/E♭3','D3','C♯3/D♭3','C3','B2','A♯2/B♭2','A2','G♯2/A♭2','G2','F♯2/G♭2','F2','E2',
    'D♯2/E♭2','D2','C♯2/D♭2','C2 Deep C','B1','A♯1/B♭1','A1','G♯1/A♭1','G1','F♯1/G♭1','F1','E1','D♯1/E♭1','D1','C♯1/D♭1','C1 Pedal C','B0','A♯0/B♭0','A0'];
    
    const Freqen=[
    4186.009,3951.066,3729.31,3520,3322.438,3135.963,2959.955,2793.826,2637.02,2489.016,2349.318,2217.461,2093.005,1975.533,1864.655,1760,1661.219,1567.982,1479.978,1396.913,1318.51,1244.508,
    1174.659,1108.731,1046.502,987.7666,932.3275,880,830.6094,783.9909,739.9888,698.4565,659.2551,622.254,587.3295,554.3653,523.2511,493.8833,466.1638,440,415.3047,391.9954,369.9944,349.2282,
    329.6276,311.127,293.6648,277.1826,261.6256,246.9417,233.0819,220,207.6523,195.9977,184.9972,174.6141,164.8138,155.5635,146.8324,138.5913,130.8128,123.4708,116.5409,110,103.8262,97.99886,
    92.49861,87.30706,82.40689,77.78175,73.41619,69.29566,65.40639,61.73541,58.27047,55,51.91309,48.99943,46.2493,43.65353,41.20344,38.89087,36.7081,34.64783,32.7032,30.86771,29.13524,27.5];
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search