【发布时间】:2018-11-11 02:26:36
【问题描述】:
我正在尝试构建一个使用样本而不是振荡器的鼓机,只是为了学习。但是,我无法安排声音在前两个节拍中按节奏播放。发生的情况是前两个节拍播放不同步,而其余节拍似乎按预期播放。播放振荡器而不是采样时不会出现此问题。
我阅读了两个时钟的故事以及我能找到的所有相关教程,但它们都适用于似乎没有出现此问题的振荡器。以下只是我尝试实现代码的一种方式 - 我尝试了 OOP 和各种函数式编程版本,但所有这些都出现了问题。
在本例中,我创建了名为 playSound() 和 playKick() 的函数。 playSound() 触发振荡器音符,而 playKick() 函数触发底鼓采样。尝试在 scheduler() 函数中切换两者,听听问题是如何发生的。
let audioContext = new (window.AudioContext || window.webkitAudioContext)();
var nextNotetime = audioContext.currentTime;
var startBtn = document.getElementById("startBtn");
var stopBtn = document.getElementById("stopBtn");
var timerID;
let kickBuffer;
loadKick('sounds/kick.wav');
function loadKick(url) {
let xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
audioContext.decodeAudioData(xhr.response, decoded => {
kickBuffer = decoded;
});
}
xhr.send();
}
function playKick(time) {
let source = audioContext.createBufferSource();
source.connect(audioContext.destination);
source.buffer = kickBuffer;
source.start(time);
}
function playSound(time) {
var osc = audioContext.createOscillator();
osc.connect(audioContext.destination);
osc.frequency.value = 200;
osc.start(time);
osc.stop(time + 0.1);
};
function scheduler() {
while(nextNotetime < audioContext.currentTime + 0.1) {
// switch between playSound and playKick to hear the problem
nextNotetime += 0.5;
playSound(nextNotetime);
// playKick(nextNotetime);
}
timerID = window.setTimeout(scheduler, 0);
}
startBtn.addEventListener('click', function() {
scheduler();
}, false);
stopBtn.addEventListener('click', function() {
clearTimeout(timerID);
}, false);
if(audioContext.state === 'suspended'){
audioContext.resume();
};
正如您所见,缓冲区在文件加载后立即被预加载,因此这不是原因的根源。任何有关如何解决此问题的建议将不胜感激。
【问题讨论】: