我正试图制造一个鼓采样机,它使用样本而不是振荡器,只是为了学习。但是我在安排前两个节拍的节奏时遇到麻烦。发生的情况是前两个节拍不同步,而其余两个节拍似乎按照预期的节奏演奏。播放振荡器而不是样本时,不会发生此问题。
我读了《两个时钟的故事》和我能找到的所有相关教程,但是它们都与振荡器一起工作,而振荡器似乎没有出现这个问题。以下只是我尝试实现代码的方法之一-我尝试了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();
};
您可以看到,在文件加载后就立即预加载了缓冲区,这不是原因的根源。任何有关如何解决此问题的建议将不胜感激。
答案 0 :(得分:0)
正在解决。
"use strict";
var audioContext = new AudioContext(),
futureTickTime = audioContext.currentTime,
counter = 1,
tempo = 120,
secondsPerBeat = 60 / tempo,
counterTimeValue = (secondsPerBeat / 4),
timerID = undefined,
isPlaying = false;
//_____________________________________________BEGIN load sound samples
let kickBuffer;
loadKick('sounds/kick.mp3');
function loadKick(url) {
let xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
audioContext.decodeAudioData(xhr.response, function(decoded) {
kickBuffer = decoded;
});
}
xhr.send();
}
function playKick(time) {
let source = audioContext.createBufferSource();
source.connect(audioContext.destination);
source.buffer = kickBuffer;
source.start(audioContext.currentTime + time);
}
//_____________________________________________END load sound samples
function scheduleSound(time) {
playKick(time)
}
function playTick() {
console.log(counter);
secondsPerBeat = 60 / tempo;
counterTimeValue = (secondsPerBeat / 1);
counter += 1;
futureTickTime += counterTimeValue;
}
function scheduler() {
if (futureTickTime < audioContext.currentTime + 0.1) {
scheduleSound(futureTickTime - audioContext.currentTime);
playTick();
}
timerID = window.setTimeout(scheduler, 0);
}
function play() {
isPlaying = !isPlaying;
if (isPlaying) {
counter = 1;
futureTickTime = audioContext.currentTime;
scheduler();
} else {
window.clearTimeout(timerID);
}
}
var playStop = document.getElementsByClassName("play-stop-button")[0];
playStop.addEventListener("click",function(){
play();
})