我正在研究如何将参数传递给setTimeout(如建议的here。) 在while循环的上下文中激活HTML5 Audio元素。
这有效:
window.setTimeout(playTone, time, phrasePitches[x]);
奇怪的是,这不起作用:
window.setTimeout(function(){
playTone(phrasePitches[x]);
}, time);
在控制台中,超时按计划进行,每次都显示:
TypeError:无法设置属性' currentTime'为null
所以出于某种原因,第二种方法不想接受数组...任何想法在这里发生了什么?
编辑...完整代码:
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++;
}
答案 0 :(得分:1)
此演示使用audiosprite⁰。我使用Audacity程序将小型MP3文件连接成一个更大的MP3文件✲。然后我以秒为单位记录了每个片段的开始和结束时间。如果手动方式看起来很艰难,那就有other ways to generate an audiosprite。
✲我在创建audiosprite之后找到MergeMP3,所以我还没有测试过它,但它看起来比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's 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>
<小时/>
✎作为TODO提到,它在本演示中尚未实现。