如何在我想要的时间内播放音频数组中的随机值

时间:2017-08-16 03:20:50

标签: javascript jquery html5

我试图播放音频数组列表序列,但有一些条件。用户将首先选择每个问题之间的随机问题和持续时间的下拉列表。然后单击“播放”按钮以运行。

当playIndex增加到3时,其持续时间开始依赖于用户的下拉列表。但它现在给我不明确。但是当playIndex = 4时它才起作用。为什么会这样?

当playIndex增加到8(播放第7个元素后)并且随机问题的数量大于4时,它将调用随机函数为playIndex和play生成随机值(数字4到7)。但我的代码只做了一次。这是为什么?

我需要尽可能多的时间来做用户想要的事情(下拉' numFollowUp')和减4,因为在第一轮中,代码从元素0到7播放,我不会这样做需要计算前4次(元素4到7)。

播放所有随机问题后,playIndex应为

如果我迷惑你,请告诉我。非常感谢你的帮助。

<select id="numFollowUp" name="numFollowUp" style=display:none>
            <option value="">Number of follow-up questions</option>
            <option value="4">4</option>
            <option value="5">5</option>
            <option value="6">6</option>
            <option value="7">7</option>
            <option value="8">8</option>
            <option value="9">9</option>
</select>
<select id="secFollowUp" name="secFollowUp" style=display:none>
            <option value="">Second between each question</option>
            <option value="10">10</option>
            <option value="11">11</option>
            <option value="12">12</option>
            <option value="13">13</option>
            <option value="14">14</option>
</select>

$("#ImageEnterVariables").on("click", function() {
        $('#ImageEnterVariables').hide();
        $("#numFollowUp").show();
        $("#secFollowUp").show();
        $("#subBut").show();
        $("#pause").hide();
    });

var intro_playList = [{
          "duration": 11,        // in seconds, real file duration
          "key": "1_hello",     
          "delayAfter": 6,    // in seconds, delay after file ended
          "stage": "intro",
          "runThrough": true,
          "random": false
        }, {
          "duration": 4,
          "key": "2_how_old",
          "delayAfter": 6,
          "stage": "intro",
          "runThrough": true,
          "random": false
        }, {
          "duration": 3,
          "key": "3_what_did_you_make",
          "delayAfter": 10,
          "stage": "intro",
          "runThrough": true,
          "random": false
        }, {
          // story_playlist
          "duration": 5,
          "key": "4_tell_me_a_story",
          "stage": "story",
          "runThrough": true,
          "random": false
        }, {
          "duration": 4,
          "key": "5_and_then_what",
          "stage": "story",
          "runThrough": true,
          "random": true
        }, {
          "duration": 2,
          "key": "6_why",
          "stage": "story",
          "runThrough": true,
          "random": true
        }, {
          "duration": 3,
          "key": "7_tell_me_more",
          "stage": "story",
          "runThrough": true,
          "random": true
        }, {
          "duration": 3,
          "key": "8_what_happened_next",
          "stage": "story",
          "runThrough": true,
          "random": true
        }, {
          "duration": 4,
          "key": "9_how_does_it_end",
          "stage": "ending",
          "runThrough": false,
          "random": false
        }, {
          "duration": 4,
          "key": "10_what_is_the_story_name",
          "stage": "ending",
          "runThrough": false,
          "random": false
        }, {
          "duration": 6,
          "key": "11_thank_you_goodbye",
          "stage": "ending",
          "runThrough": false,
          "random": false
        }];



$(document).ready(function() {
// Version 1
        var audioElement = document.createElement('audio');
        audioElement.addEventListener("ended", playAudio);

        var audioSrc = "sound/"
        var audioType = ".wav";
        var defaultNumFollowUp = 1; // default number of random question, if user this used the dropdown
        var defaultSecFollowUp = 10; // default delay (seconds) between random questions, if user this used the dropdown

        // Analyse the scenario by getting indexes in different arrays.
        var endingArr = [];
        var runThroughArr = [];
        var randomArr = [];

        for(i = 0; i < intro_playList.length ; i++){

            if(intro_playList[i].stage === "ending"){ endingArr.push(i); }
            if(intro_playList[i].runThrough){ runThroughArr.push(i); }
            if(intro_playList[i].random){ randomArr.push(i); }
        }

        function getAudio(n){
            audioElement.src = audioSrc + intro_playList[n].key + audioType;
            audioElement.load();
            audioElement.play();

            return intro_playList[n]; // return the object
        }

        // Onload indexes.
        var playIndex = 0;
        var randomplayCount = 0;
        var endingCount = 0;

        // Interval variables
        var playInterval;
        var time = new Date().getTime();
        console.log(time + " is old time");

        // User inputs
        var numFollowUp = parseInt($("#numFollowUp").val());
        if(isNaN(numFollowUp)){ numFollowUp = defaultNumFollowUp; }

        var secFollowUp = parseInt($("#secFollowUp").val());
        if(isNaN(secFollowUp)){ secFollowUp = defaultSecFollowUp; }

$("#play").on("click", playAudio);

function playAudio(){

            playInterval = setInterval(function(){ // Every 0.1 second, do setInterval
                var now = new Date().getTime();
                //console.log(now + " now time");

                if(now > time){
                    // First "run throught" plays all the audios in order, except the "ending" ones.
                    // playIndex = 0 in the first place
                    if(playIndex < runThroughArr.length){
                        var audioIndex = playIndex;
                        console.log("================================== RUN THROUGH!");
                        console.log("audioIndex is " + audioIndex);

                        playIndex++;

                    }else if (playIndex >= runThroughArr.length && randomplayCount <= numFollowUp){
                        var audioIndex = randomArr[ Math.floor(Math.random()*(randomArr.length - 1)) ];

                        console.log("================================== RUN random!");

                        // Increment index for next iteration
                        randomplayCount++;
                        console.log(randomplayCount);

                    }else if (randomplayCount >= defaultNumFollowUp && endingCount < endingArr.length ){
                        var audioIndex = endingArr[endingCount];

                        console.log("================================== RUN ending!");

                        // Increment index for next iteration
                        endingCount++;
                    }

                    // STOP INTERVAL!
                    if( endingCount === endingArr.length ){
                        clearInterval(playInterval);
                        console.log("=========== Interval stopped.");

                        // Reset onload indexes.
                        playIndex = 0;
                        randomplayCount = 0;
                        endingCount = 0;
                    }

                    // Prepare the audio file.
                    var audioObj = getAudio(audioIndex);

                    if(audioObj.stage === "intro"){
                    // set a new trigger time
                        time = new Date().getTime() + (audioObj.duration * 1000) + (audioObj.delayAfter * 1000);
                        console.log(time + " is time");

                    }else{

                        time = new Date().getTime() + (audioObj.duration * 1000) + (secFollowUp * 1000);
                    }

                    // Show what is actually playing
                    console.log("Playing "+ audioObj.key + " after " + audioObj.delayAfter + " seconds");
                    console.log("Stage: "+ audioObj.stage);

                } // if(now > time)

            }, 100); // playInterval, The interval duration of 0,1 second is to ensure accuracy if you set a duration or "delayAfter" using float seconds like 2.5.

        } // playAudio

        // Preload all audios to make sure they are available since timing is sometimes short.
        var preloadArr = [];

        for(i = 0; i < intro_playList.length; i++){

            var audioElementPreload = document.createElement('audio');
            audioElementPreload.src = audioSrc + intro_playList[i].key + audioType;
            audioElementPreload.load();
            preloadArr.push(audioElementPreload);
        }
});

2 个答案:

答案 0 :(得分:1)

我从头开始完全重写你的代码...... 第二次!
我认为这真的是一个很好的项目......还有一个很好的编码挑战。

在第二次教导中,我在使用setTimeout()的第一个延迟“概念”中看到了几个问题:

  1. 音频长度超过超时延迟被削减...两个文件之间没有超时。
  2. 即使音频不长于延迟,此延迟也会被文件长度部分“吸收”。
  3. 更改“方案”,例如添加更多随机问题,需要代码中的tweek。
  4. 在随机“舞台”之后播放的“结尾”需要为每个结尾文件嵌套setTimeout(),这太可怕了。
  5. 所以我认为使用setInterval()来检查“实际时间”与脚本在每次迭代时设置开始下一个音频(基于文件持续时间+延迟)的时间相比...将是一个想法。

    它有效!它简化了代码 所有“场景”信息现在都在对象数组中。

    CodePen

    var audioSrc = "https://www.bessetteweb.com/SO/45704602/";    // Path to the audio files
    var audioType = ".mp3";
    
    var default_numFollowUp = 4;  // default number of random question, if user this used the dropdown
    var default_secFollowUp = 10;  // default delai (seconds) between random questions, if user this used the dropdown
    
    // Create the audio element
    var audioElement = document.createElement('audio');
    
    // Analyse the scenario by getting indexes in different arrays.
    var endingArr = [];
    var runThoughArr = [];
    var randomArr = [];
    for(i=0;i<intro_playList.length;i++){
      if(intro_playList[i].stage == "ending"){ endingArr.push(i); }
      if(intro_playList[i].runThough){ runThoughArr.push(i); }
      if(intro_playList[i].random){ randomArr.push(i); }
    }
    
    // Get an audio and play it
    function getAudio(n){
      audioElement.src = audioSrc + intro_playList[n].key + audioType;
      audioElement.load();
      audioElement.play();
      console.log(JSON.stringify(intro_playList[n]));
      return intro_playList[n]; // return the object
    }
    
    // Onload indexes.
    var playIndex = 0;
    var randomplayCount = 0;
    var endingCount = 0;
    
    // Interval variables
    var playInterval;
    var time = new Date().getTime();
    
    
    // Function to start the interval check to play a file
    function playAudio(){
    
      // User inputs
      var numFollowUp = parseInt($("#numFollowUp").val() );
      if(isNaN(numFollowUp)){ numFollowUp = default_numFollowUp;}
    
      var secFollowUp = parseInt($("#secFollowUp").val() );
      if(isNaN(secFollowUp)){  secFollowUp = default_secFollowUp; }
    
      // Ensure no other interval runs...
      clearInterval(playInterval);
    
      // Set the interval.
      playInterval = setInterval(function(){
    
        var now = new Date().getTime();
        if(now > time){
    
          // First "run throught" plays all the audios in order, except the "ending" ones.
          if( playIndex < runThoughArr.length){
            var audioIndex = playIndex;
            console.log("==================================================================== RUN TROUGH!");
    
            // Increment index for next iteration
            playIndex++;
          }
    
          // Random!
          else if( playIndex >= runThoughArr.length && randomplayCount < numFollowUp ){
            //var audioIndex = getRandomIndex();
            var audioIndex = randomArr[ Math.floor(Math.random()*(randomArr.length-1)) ];
            console.log("==================================================================== RANDOM! ("+randomplayCount+"/"+numFollowUp+")");
    
            // Increment index for next iteration
            randomplayCount++;
          }
    
          // Ending
          else if( randomplayCount >= numFollowUp && endingCount < endingArr.length ){
            var audioIndex = endingArr[endingCount];
            console.log("==================================================================== ENDING!");
    
            // Increment index for next iteration
            endingCount++;
          }
    
          // STOP INTERVAL!
          if( endingCount == endingArr.length ){
            clearInterval(playInterval);
            console.log("=========== Interval stopped.");
    
            // Reset onload indexes.
            playIndex = 0;
            randomplayCount = 0;
            endingCount = 0;
          }
    
          // Prepare the audio file.
          var audioObj = getAudio(audioIndex);
    
          if(audioObj.stage == "intro"){
            // set a new trigger time
            time = new Date().getTime() + (audioObj.duration * 1000) + (audioObj.delayAfter * 1000);
          }else{
            time = new Date().getTime() + (audioObj.duration * 1000) + (secFollowUp * 1000);
          }
          // Show what is actually playing
          console.log("Playing "+ audioObj.key);
          console.log("Stage: "+ audioObj.stage);
    
        } // if(now > time)
    
      },100); // interval
    
    } // playAudio()
    
    // Preload all audios to make sure they are available since timing is sometimes short.
    var preloadArr = [];
    for(i=0;i<intro_playList.length;i++){
      var audioElementPreload = document.createElement('audio');
      audioElementPreload.src = audioSrc + intro_playList[i].key + audioType;
      audioElementPreload.load();
      preloadArr.push(audioElementPreload);
    }
    
    // Play button handler
    $("#play").on("click", playAudio);
    

答案 1 :(得分:1)

如果正确解释问题,您可以使用.queue().promise().then()并重复安排对完整数组执行操作while循环{{1}和.splice() .splice()Math.random()将原始数组的N个元素作为新数组,从切片数组中选择一个伪随机元素,重复原始任务,然后使用重复任务原始数组来完成程序。

&#13;
&#13;
Math.floor()
&#13;
var arr = [...Array(9).keys()],
  currentRandomTracks = [],
  notify = function notify(message) {
   $("body").append(message + "<br>")
  }
  
var player = $({});

function playTracks(tracks) {
  return player.queue("tracks", $.map(tracks, function(el, index) {
    return function(next) {
      return new Promise(function(resolve) {
        // do stuff 
        setTimeout(function() {
          resolve(el);
        }, Math.floor(Math.random() * 750))
      }).then(function(value) {
        notify(value);
        // call `next` when synchronous or asynchronous task completes
        return next()
      })
    }
  })).dequeue("tracks").promise("tracks")
}

function handleRandomQueue() {
    // select N elements from `arr`
    if (currentRandomTracks.length === 0) {
      currentRandomTracks = arr.slice(6);
      var randomTracks = [];
      // select random elements from `currentRandomTracks`
      while (currentRandomTracks.length) {
        randomTracks[randomTracks.length] = currentRandomTracks
          .splice(Math.floor(Math.random() * currentRandomTracks.length), 1)
          .pop();
      }
      notify("original playlist done playing, "
        + "starting playing random indexes " 
        + currentRandomTracks.toString() + " next"
      );
      return playTracks(randomTracks)
    } else {
      notify("random playback playlist complete, "
        + "stating playing original playlist " 
        + arr.toString()
      );
      // perform task on original array, again
      return playTracks(arr);
    }
  }
  
  function handleRepeatOriginalQueue() {
    notify("original and random playlist playback complete");
    return playTracks(arr);
  }
  
  function handleQueueComplete() {
    // procedure complete
    notify("original, random, "
      + "and second original playlist playback complete"
    );
  }

$(function() {

playTracks(arr)
  .then(handleRandomQueue)
  .then(handleRepeatOriginalQueue)
  .then(handleQueueComplete)
  .fail(function err(err) {
    console.error(err)
  })
})
&#13;
&#13;
&#13;