我正在使用网络音频和JavaScript完成一个节拍/采样垫项目。当我单击样本板时,我希望它立即发出声音,这在桌面版本上工作正常,但是,在移动设备上,样本只有在我将手指从屏幕上抬起后才会发出声音。然后,这会产生某种滞后,例如,您绝对无法及时播放任何音乐。有没有办法让样本在移动设备上按下后立即发出声音?我发现"鼠标按下"事件似乎最适合桌面,但我无法获得与我在移动设备上尝试的任何内容相同的结果。
请随时在这里查看Beat pad项目:http://beatpad.dwcreate.co.uk/
如果需要,我稍后会发布代码。
非常感谢任何可以帮助我解决这个问题的人!
Audio
元素似乎在 Apple Touch 设备上存在延迟问题......不确定其他人。AudioBuffer
将跨浏览器提供更可靠的即时播放。 经过一番摆弄,似乎"touchstart"事件必须绑定在文档上,并且在绑定到元素上时不起作用。
// samples identified by keyboard key code
const samples = [49,50,51,52,53,54,55,56,57,48,45,61,113,119,101,114,116,121,117,105,111,112,91,93,97,115,100,102,103,104,106,107,108,59,39,122,120,99,118,98,110,109,44,46,47]
// audio contect for decoding and playback
const ctx = new (window.AudioContext || window.webkitAudioContext)({ latencyHint: 'playback' })
// decoded AudioBuffers we'll create for each sample
audioBuffers = {}
// keyboard keys to render
keys = {}
// track download/decode progress
let totalLoaded = 0
init()
function init() {
samples.forEach(async keyCode => {
const url = `https://cøder.com/static/61881209/${keyCode}.mp3`
const buffer = await (await fetch(url)).arrayBuffer()
ctx.decodeAudioData(buffer, decoded => {
audioBuffers[keyCode] = decoded
fileLoaded()
})
})
}
// keyboard press
document.addEventListener('keypress', playSample)
function fileLoaded() {
totalLoaded++
document.querySelector('#progress').innerText = `Samples Loaded: ${totalLoaded} / ${samples.length}`
if (totalLoaded === samples.length) {
initKeyboard()
}
}
function playSample({ keyCode }) {
// play audio sample from beginning
const [audioBuffer, key] = [audioBuffers[keyCode], keys[keyCode]]
if (audioBuffer) {
const bufferSource = ctx.createBufferSource()
bufferSource.buffer = audioBuffer;
bufferSource.connect(ctx.destination);
bufferSource.start(0);
requestAnimationFrame(_ => {
key.classList.remove('pressed')
requestAnimationFrame(_ => {
key.classList.add('pressed')
})
})
}
}
// draw keyboard on screen
function initKeyboard() {
const keyboard = document.createElement('div')
keyboard.className = 'keyboard'
let row = 0 // keyboard row
const breakOn = ['q', 'a', 'z'] // start new row
// render each keyboard key
samples.forEach(keyCode => {
const char = String.fromCharCode(keyCode)
const key = document.createElement('div')
key.className = 'key'
key.innerText = char
key.dataset.code = keyCode
// start new row
if (breakOn.includes(char)) {
row++
key.style.clear = 'both'
key.style.marginLeft = `${20*row}px`
}
keys[keyCode] = key
keyboard.append(key)
})
// bind click or touch if it's a tablet
if ('ontouchstart' in window) {
document.addEventListener('touchstart', handleClick)
} else {
document.addEventListener('mousedown', handleClick)
}
function handleClick(e) {
const {dataset: {code}} = e.target
if (code) {
playSample({ keyCode: code })
}
}
document.body.innerHTML = ''
document.body.append(keyboard)
}
body {
font-family: 'open sans light', arial, sans-serif;
background: #f9f9f9;
}
.keyboard {
width: 620px;
overflow: hidden;
white-space: nowrap;
}
.key {
background: #fff;
cursor: pointer;
height: 40px;
width: 40px;
margin: 2px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #ccc;
float: left;
border-radius: 6px;
user-select: none;
}
.key.pressed {
animation: keyPress .5s ease-out;
}
@keyframes keyPress {
0% {
background: lime;
}
100% {
background: #fff;
}
}
<div id="progress">Loading...</div>
根据Mozilla MDN,您可能正在寻找touchstart
事件。
function onTouchQuick() {
// ...
}
element.addEventListener("touchstart", onTouchQuick);