【问题标题】:Using a switch case inside for loop to play audio too quick在 for 循环中使用开关盒播放音频太快
【发布时间】:2018-03-18 13:28:18
【问题描述】:

我试图通过循环数组并将数组拆分为每个数组来播放声音,然后使用 switch case 来检测数组中的内容。 函数 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;

    }
}}

它的功能运行良好,但显然播放的声音太快了。有没有办法解决这个问题?

【问题讨论】:

  • wav 文件有多大?
  • @zer00ne 差不多 1 ​​秒。

标签: javascript


【解决方案1】:

我假设你想听到一个接一个的声音?

这样不行。 假设数组中的第一个数字是:0。
所以声音 0 被播放。
但是,由于您遍历数组,并且您到达下一个数字,例如。 2:声音 2 在之后立即播放。
在开始下一个 play() 之前,循环不会等待第一个声音结束。

您可以做的是修改循环以等待音频结束事件。
例如:

var audio0 = document.getElementById("myAudio");
audio0.onended = function() {
  alert("The audio has ended");
};

【讨论】:

  • 是的,这正是我的代码所发生的事情。你能用我的代码给我看一个例子吗?我对 JS 很陌生
【解决方案2】:

尝试使用音频精灵。我确定有一个应用程序或其他任何东西可以以编程方式执行某些任务,但请注意第 1 步和第 2 步是手动完成的。

  1. 获取一组音频文件,然后使用Audacityonline service 将它们合并到一个文件中。

  2. 接下来,获取音频文件中每个剪辑的开始时间,并将它们存储在一个数组中。

  3. 以下 Demo 将获取文件和数组,生成 HTML 布局,为每个与数组参数对应的剪辑创建一个按钮。所以当一个按钮被点击时,它只会播放一段音频精灵(音频文件)。

  4. 这个演示中的音频精灵没有很好地编辑,我只是​​为了演示一切是如何工作的。时间依赖于 timeupdate 事件,该事件大约每 250 毫秒给或取检查播放时间。因此,如果您想制作更准确的开始和结束时间,请尝试在剪辑之间留出 250 毫秒的间隙。

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

【讨论】:

  • 我只希望 switch-case 等待音频,并在第一个 case 完成后转到下一个 case。
  • switch 只是if/if else/else 条件的一种脆弱形式。异步加载音频文件的限制以及基本的timeupdate 事件、setTimeoutsetInterval 方法无法处理短突发的音频然后恢复到准确的时间。 除非您使用Web Audio API 并查看此特定demo 的来源,祝您好运。
【解决方案3】:

尝试使用计时器:

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

像这样使用 setTimeout 函数

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-31
相关资源
最近更新 更多