Передача аргументов в setTimeout: один метод не работает (JS)

1

Я изучаю, как передавать аргументы в setTimeout (как указано здесь.) В контексте цикла while, который активирует элемент HTML5 Audio.

Это работает:

window.setTimeout(playTone, time, phrasePitches[x]);

Любопытно, что это не работает:

window.setTimeout(function(){
    playTone(phrasePitches[x]);
}, time);

В консоли тайм-ауты выполняются по расписанию, каждый из которых отображает:

TypeError: невозможно установить свойство currentTime 'null

Поэтому по какой-то причине второй метод не хочет принимать массив... любая идея, что здесь происходит?

EDIT... полный код:

function playTone(tone){
        var tone = document.getElementById(tone);
        tone.currentTime = 0;
        tone.play();
    };

var pitchSet = new Array ("C3","D3","E3","F3","G3","A3","B3","C4");

fyshuffle (pitchSet);  // The Fischer-Yater shuffle function
    var i = 0;
    var phrasePitches = new Array();
    while (i < 4) { 
        phrasePitches.push(pitchSet[i]);
        i++; 
    }

var x=0;
var time = 0;
while(x<4){
//  window.setTimeout(playTone, time, phrasePitches[x]);  // This works.
    window.setTimeout(function(){
        playTone(phrasePitches[x]);
    }, time);
    time += 2000;
    x++;        
}
Теги:
arguments

1 ответ

1
Лучший ответ

Audiosprites

В этой демонстрации используется аудиосессия. Я использовал программу Audacity для объединения небольших файлов MP3 в один более крупный файл MP3. Затем я принял во внимание каждое начало и конец фрагмента в секундах. Существуют и другие способы создания аудиосприта, если ручной способ кажется трудным.

✲ Я нашел MergeMP3 после создания audiosprite, поэтому я еще не тестировал его, но он выглядит намного проще, чем Audacity.

Детали прокомментированы в демо и заметках, соответствующих ссылкам

демонстрация

// Reference the <audio>
var fx = document.querySelector('#fx');

/* Reference the <fieldset> (can be any element with an
|| endtag: <tag></tag>
*/
var panel = document.querySelector('#panel');

/* Map the audiosprite frags in an object of arrays 
|| Each array represents a frag which consists of: 
|| 'key': [start time, end time]¹
|| TODO: replace object literal with ES6 Map²
*/
var sprite = {
  'all': [0, 27],
  'click': [0, .45],
  'bell': [.65, 7.4],
  'elevator': [7.5, 9.7],
  'sonar': [10, 27]
};

// Declare default value of end time
var end = 0;

// Register the <audio> on the loadeddata event³...
fx.addEventListener('loadeddata', function(e) {

  /* Object.keys chained to .forEach()⁴ iterates through
  || 'sprite' properties (key/value pairs).
  */
  Object.keys(sprite).forEach(function(key, index) {

    /* On each iteration, generate a <button> inside the
    || <fieldset>
    || Note the use of a template literal⁵
    || TODO: Delegate⁶ click events to panel to avoid
    || inline attribute event handlers 
    */
    panel.innerHTML += '<button onclick="effect('${key}')">${key}</button>';
  });
}, false);

// Register the <audio> on timeupdate event⁷...
fx.addEventListener('timeupdate', function(e) {

  /* timeupdate occurs when playing position changes
  || check if the currentTime⁸ property of <audio> 
  || is more than the value of 'end' 
  || ('end' is the second value of a frag: sprite[key][1])
  || If it is, pause the <audio>
  */
  if (fx.currentTime > end) {
    fx.pause();
  }
}, false);

/* This function passes the string value of 'key' 
|| in sprite object
|| Each 'key' has a value of an array containing an start
|| time and an end time. 
|| In short, 'key' is a reference to a frag.
*/
function effect(key) {

  // if the 'key' in 'sprite' object exists...
  if (sprite[key]) {

    /* The currentTime of <audio> is 
    || the first value of 'key' 
    */
    fx.currentTime = sprite[key][0];

    // Assign 'end' the second value of 'key' 
    end = sprite[key][1];

    /* Play <audio>
 	  || Note at this point, if done conventionally by
    || reloading the .src for each change to a separate
    || frag, fx.load() would need to be invoked
	  || as well, thereby incurring another HTTP request
	  */
    fx.play();
  }
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1, user-scalable=no">
  <style>

  </style>
</head>

<body>
  <section>
    <!-- 
An audiosprite⁰ is an audio file that is actually a
concatenation of multiple sound files 
(from now on refered to as frags) played at 
different times throughout its duration. 

The advantages are that:
- the file is downloaded once then cached
- the src doesn't change thus only one HTTP request needed

If done the conventional way with multiple frags there 
would be:
- several downloads for smaller files 
- the added HTTP request everytime the src attribute changes
  its url
-->
    <audio id='fx' src='http://vocaroo.com/media_command.php?media=s0L5VMshEG3E&command=download_mp3' controls></audio>
    <fieldset id='panel'>
      <legend>Effects</legend>
    </fieldset>
  </section>
  <!-- 
If using JS on the same page rather than externally,
place the JS here within a <script> block:
<script>
...:::JS code here:::...
</script>
-->

</body>

</html>


Рекомендации

audiosprite

¹ пары ключ/значение

² Карта ES6 ✎

³ загруженное событие

Object.keys(). ForEach()

шаблонный литерал

Событие Делегация ✎

⁷ время ожидания

currentTime

✎ Упомянутый как TODO, он не был реализован в этой демонстрации.

  • 0
    @zerOOne ... хорошо! это удивительно, спасибо! Я определенно буду использовать эту концепцию в будущем. Отличный урок, который вы собрали здесь, вы должны опубликовать где-нибудь в блоге :)
  • 0
    @GregoryTippett спасибо, сэр. Не забудьте принять этот ответ, если он решил вашу проблему, нажав ✔. Удачного кодирования.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню