Я пытаюсь построить драм-машину, которая использует сэмплы вместо осцилляторов, просто для обучения. У меня, однако, возникают проблемы с планированием воспроизведения звуков в ритме для первых двух ударов. Что происходит, так это то, что первые два удара воспроизводятся несинхронно, а остальные, кажется, играют в ритме, как и предполагалось. Эта проблема не возникает при воспроизведении осцилляторов вместо сэмплов.
Я прочитал «Повесть о двух часах» и все соответствующие учебные пособия, которые я смог найти, но все они работают с осцилляторами, которые, похоже, не демонстрируют эту проблему. Следующее является лишь одним из способов, которыми я пытался реализовать код - я пробовал ООП и различные версии функционального программирования, но проблема возникает со всеми из них.
В этом примере я использовал функции playSound () и playKick (). playSound () запускает ноту осциллятора, тогда как функция playKick () запускает сэмпл. Попробуйте переключиться между ними в функции планировщика (), чтобы узнать, как возникла проблема.
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();
};
Как видите, буфер предварительно загружен, как только файл загружен, так что это не является причиной причины. Будем весьма благодарны за любые предложения о том, как решить проблему.