我正在组装一个鼓机/音序器,虽然音序器的主要功能运行良好,但当音序器第一次播放时,我嵌入到每个鼓单元中的音频确实有明显的滞后。它似乎在第一个节拍后自我纠正,一切正常播放,直到其他声音添加到模式中。
我有三行表格单元格,每一行代表不同的鼓声。当用户使用所有可用的声音构建一个鼓模式时,循环最终似乎失去了同步,一些声音比其他声音晚了几分之一秒,但后来又进行了自我纠正。我主要担心的是样本的回放不一致。
我已经将标记嵌入到元素中,并将preload属性设置为auto。
<table class="pad">
<tbody>
<tr>
<td class="kick sounds">
<audio preload="auto" src="https://raw.githubusercontent.com/wesbos/JavaScript30/master/01%20-%20JavaScript%20Drum%20Kit/sounds/kick.wav"></audio>
</td>
</tr>
</tbody>
</table>
因此,每行有8个表单元格,每个单元格都具有与上面相同的格式(嵌入了元素)。诚然,我可以想象我的结构方式是相当低效的,使用web音频API会更好,但我还没有学习API。在JS中有什么我可以做的,可以让这些音频样本的播放速度更快?
编辑:这是序列器代码。它循环遍历每个元素,并检查是否有选定的单元格。如果是,则播放该元素的音频文件。如果不是,则跳到下一列。
class Sequencer {
playButton = btn;
clearButton = clear;
sounds = Array.from(sounds);
kicks = Array.from(kicks);
hihats = Array.from(hihats);
snares = Array.from(snares);
currentBeatIndexKick = 0;
currentBeatIndexHiHat = 0;
currentBeatIndexSnare = 0;
isPlaying = false;
constructor(msPerBeat) {
this.msPerBeat = msPerBeat;
this.playButton.addEventListener('click', () => this.toggleStartStop())
this.clearButton.addEventListener('click', () => this.clear())
this.sounds.forEach(sound => {
sound.addEventListener('click', e => {
if (((e.target.classList.contains('kick')) || (e.target.classList.contains('hihat')) || (e.target.classList.contains('snare'))) && !e.target.classList.contains('selected')) {
e.target.classList.add('selected');
} else {
e.target.classList.remove('selected');
}
})
})
}
toggleStartStop() {
if (this.isPlaying) {
this.stop();
} else {
this.start();
}
}
clear() {
this.kicks.forEach(kick => {
if (kick.classList.contains('selected')) {
kick.classList.remove('selected');
}
});
hihats.forEach(hihat => {
if (hihat.classList.contains('selected')) {
hihat.classList.remove('selected');
}
});
snares.forEach(snare => {
if (snare.classList.contains('selected')) {
snare.classList.remove('selected');
}
});
this.stop();
console.clear();
}
stop() {
this.isPlaying = false;
this.currentBeatIndexKick = 0;
this.currentBeatIndexHiHat = 0;
this.currentBeatIndexSnare = 0;
this.playButton.innerText = 'Play';
}
start() {
this.isPlaying = true;
this.playCurrentNoteAndSetTimeoutKick() // kicks
this.playCurrentNoteAndSetTimeoutHiHats() // hihats
this.playCurrentNoteAndSetTimeoutSnares() // snares
this.playButton.innerText = 'Stop';
}
playCurrentNoteAndSetTimeoutKick() {
if (this.isPlaying && this.kicks[this.currentBeatIndexKick].classList.contains('selected')) {
this.kicks[this.currentBeatIndexKick].childNodes[1].play();
setTimeout(() => {
this.toNextBeatKicks();
this.playCurrentNoteAndSetTimeoutKick();
}, this.msPerBeat)
}
if (this.isPlaying && !this.kicks[this.currentBeatIndexKick].classList.contains('selected'))
setTimeout(() => {
this.toNextBeatKicks();
this.playCurrentNoteAndSetTimeoutKick();
}, this.msPerBeat)
}
playCurrentNoteAndSetTimeoutHiHats() {
if (this.isPlaying && this.hihats[this.currentBeatIndexHiHat].classList.contains('selected')) {
this.hihats[this.currentBeatIndexHiHat].childNodes[1].play();
setTimeout(() => {
this.toNextBeatHiHats();
this.playCurrentNoteAndSetTimeoutHiHats();
}, this.msPerBeat)
}
if (this.isPlaying && !this.hihats[this.currentBeatIndexHiHat].classList.contains('selected'))
setTimeout(() => {
this.toNextBeatHiHats();
this.playCurrentNoteAndSetTimeoutHiHats();
}, this.msPerBeat)
}
playCurrentNoteAndSetTimeoutSnares() {
if (this.isPlaying && this.snares[this.currentBeatIndexSnare].classList.contains('selected')) {
this.snares[this.currentBeatIndexSnare].childNodes[1].play();
setTimeout(() => {
this.toNextBeatSnares();
this.playCurrentNoteAndSetTimeoutSnares();
}, this.msPerBeat)
}
if (this.isPlaying && !this.snares[this.currentBeatIndexSnare].classList.contains('selected'))
setTimeout(() => {
this.toNextBeatSnares();
this.playCurrentNoteAndSetTimeoutSnares();
}, this.msPerBeat)
}
toNextBeatKicks() {
this.currentBeatIndexKick = ++this.currentBeatIndexKick % this.kicks.length;
}
toNextBeatHiHats() {
this.currentBeatIndexHiHat = ++this.currentBeatIndexHiHat % this.hihats.length;
}
toNextBeatSnares() {
this.currentBeatIndexSnare = ++this.currentBeatIndexSnare % this.snares.length;
}
}
const sequencer = new Sequencer(213)
发布于 2020-08-09 13:36:14
我认为你可能需要做的是以编程的方式播放音频文件。如果不让我们更多地访问你的代码,就很难理解你的sequencer是如何工作的,我的方法是一旦用户选择了序列,就通过编程播放音频文件。我会分配一个变量来播放,一旦在你的音序器上选择了这些步骤。
var audio = new Audio('audio_file.mp3');
audio.play();
将在序列上调用audio.play。我不确定这是否有帮助,但我认为这是您所指的api的一部分。
https://stackoverflow.com/questions/63322702
复制相似问题