1

I'm trying to play a sound by looping an array and split an array into each array, and then using switch case to detect what's in the array. function keeper() {

number2 = get.num;
sNumber = number2.toString();
output = [];



for ( i = 0, len = sNumber.length; i < len; i ++) {
    output.push(+sNumber.charAt(i));
    console.log(output);

    switch (output[i]){
        case 0:
        console.log('0');
        audio0 = new Audio('logo/Q0.wav');
        audio0.play();
        break;
        case 1:
        console.log('1');
        audio1 = new Audio('logo/Q1.wav');
        audio1.play();
        break;
        case 2:
        console.log('2');
        audio2 = new Audio('logo/Q2.wav');
        audio2.play();
        break;
        case 3:
        console.log('3');
        audio3 = new Audio('logo/Q3.wav');
        audio3.play();
        break;
        case 4:
        console.log('4');
        audio4 = new Audio('logo/Q4.wav');
        audio4.play();
        break;
        case 5:
        console.log('5');
        audio5 = new Audio('logo/Q5.wav');
        audio5.play();
        break;

    }
}}

The function it works just fine, but apparently the sound thats played out it too quick. is there any solution to fix this?

Max13
  • 95
  • 1
  • 9

3 Answers3

1

I'm assuming you want to hear the sounds after each other?

That doesn't work like this. Lets say the first number in the array is: 0.
So sound 0 gets played.
But, since you loop through the array, and you reach the next number, eg. 2: sound 2 gets played immediately after.
The loop doesn't wait for the first sound the finish before starting the next play().

what you could do is modify the loop to wait for the audio ended event.
for example:

var audio0 = document.getElementById("myAudio");
audio0.onended = function() {
  alert("The audio has ended");
};
  • Yes, that's exactly what happened to my code. Can you show me an example with my code? i'm quite new with JS – Max13 Mar 18 '18 at 14:02
0

Try to use a timer:

for (var i = 1; i <= 3; i++) {
    (function(index) {
        setTimeout(function() { alert(index); }, i * 1000);
    })(i);
}

Use the setTimeout fuction like that

Marius Vuscan
  • 170
  • 1
  • 2
  • 16
0

Try using an audio sprite. I'm sure there's an app or whatever to do certain tasks programmatically but be aware step 1 and 2 are done manually.

  1. Take a group of audio files and either use Audacity or an online service to join them into one file.

  2. Next, get the start times of each clip of the audio file and store them in an array.

  3. The following Demo will take the file and array, generate the HTML layout, create a button for each clip that corresponds to the array parameter. So when a button is clicked it will play only a clip of the audio sprite (the audio file).

  4. The audio sprite in this Demo was not edited very well, I just made it to demonstrate how everything works. The timing relies on the timeupdate event which checks the playing time about every 250ms give or take. So if you want to make a more accurate start and end times, try leaving a gap of 250ms between clips.

Details commented in Demo

Demo

// Store path to audio file in a variable
var xFile = 'https://storage04.dropshots.com/photos7000/photos/1381926/20180318/175955.mp4'

// Store cues of each start time of each clip in an array
var xMap = [0, 1.266, 2.664, 3.409, 4.259,4.682,  5.311, 7.169, 7.777, 9.575, 10.88,11.883,13.64, 15.883, 16.75, 17, 17.58];

/* Register doc to act when the DOM is ready but before the images
|| are fully loaded. When that occurs, call loadAudio()
*/
document.addEventListener('DOMContentLoaded', function(e) {
  loadAudio(e, xFile, xMap);
});

/* Pass the Event Object, file, and array through
|| Make a Template Literal of the HTML layout and the hidden
|| <audio> tag. Interpolate the ${file} into the <audio> tag.
|| Insert the TL into the <body> and parse it into HTML.
== Call generateBtn() function...
*/
function loadAudio(e, file, map) {
  var template = `
<fieldset class='set'>
  <legend>Sound FX Test Panel</legend>
</fieldset>
<audio id='sndFX' hidden>
  <source src='${file}' type='audio/wav'>
</audio>`;
  document.body.insertAdjacentHTML('beforeend', template);
  generateBtn(e, map);
}

/* Pass the Event Object and the array through
|| Reference fieldset.set
|| create a documentFragment in order to speedup appending
|| map() the array...
|| create a <button>
|| Set btn class to .btn
|| Set button.btn data-idx to the corresponding index value of
|| map array.
|| Set button.btn text to its index number.
|| Add button.btn to the documentFragment...
|| return an array of .btn (not used in this demo)
== Call the eventBinder() function...
*/
function generateBtn(e, map) {
  var set = document.querySelector('.set');
  var frag = document.createDocumentFragment();
  map.map(function(mark, index, map) {
    var btn = document.createElement('button');
    btn.className = 'btn';
    btn.dataset.idx = map[index];
    btn.textContent = index;
    frag.appendChild(btn);
    return btn;
  });
  set.appendChild(frag);
  eventBinder(e, set, map);
}

/* Pass EventObject, fieldset.set, and map array through
|| Reference the <audio> tag.
|| Register fieldset.set to the click event
|| if the clicked node (e.target) class is .btn...
|| Determine the start and end time of the audio clip.
== Call playClip() function
*/
function eventBinder(e, set, map) {
  var sFX = document.getElementById('sndFX');
  set.addEventListener('click', function(e) {
    if (e.target.className === 'btn') {
      var cue = parseFloat(e.target.textContent);
      var start = parseFloat(e.target.dataset.idx);
      if (cue !== (map.length - 1)) {
        var end = parseFloat(e.target.nextElementSibling.dataset.idx);
      } else {
        var end = parseFloat(sFX.duration);
      }
      playClip.call(this, sFX, start, end);
    } else {
      return false;
    }
  });
}

/* Pass the reference to the <audio> tag, start and end of clip
|| pause audio
|| Set the currentTime to the start parameter
|| Listen for timeupdate event...
|| should currentTime meet or exceed the end parameter...
|| pause <audio> tag.
*/
function playClip(sFX, start, end) {
  sFX.pause();
  sFX.currentTime = start;
  sFX.play();
  sFX.ontimeupdate = function() {
    if (sFX.currentTime >= end) {
      sFX.pause();
    }
  }
  return false;
}
Community
  • 1
  • 1
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • I just want the switch-case wait for the audio and go for the next case when the first case its done. – Max13 Mar 19 '18 at 10:12
  • `switch` is just a fragile form of `if/if else/else` conditions. The limitations of asynchronous loading of audio files and the primitive `timeupdate` event, `setTimeout`, and `setInterval` methods cannot handle short bursts of audio and then recover to an exact time. *Unless* you use [**Web Audio API**](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API) and take a look at the source of this particular [demo](http://webaudioapi.com/samples/crossfade-playlist/) Good luck. – zer00ne Mar 22 '18 at 19:30