在移动设备上按下时,如何使Web Audio元素立即发出声音? [英] How to make a Web Audio element sound instantly when pressed on mobile?

查看:95
本文介绍了在移动设备上按下时,如何使Web Audio元素立即发出声音?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用网络音频和JavaScript完成拍子/采样垫项目.当我单击一个采样垫时,我希望它能够立即发出声音,并且在台式机上可以正常工作,但是,在移动设备上,只有当我将手指从屏幕上移开时,采样才会发出声音.这样会造成各种各样的延迟,例如,您肯定无法及时播放任何音乐.有没有一种方法可以让样本在移动设备上按下后立即立即响起?我发现"mousedown"事件似乎最适合台式机,但是对于移动设备,我无法获得相同的结果.

I am finishing up a beat/sample pad project using web audio and JavaScript. When I click on a sample pad, I want it to sound instantly, and this works fine on the desktop version, however, on mobile, the sample will only sound once I have lifted my finger away from the screen. This then creates a lag of sorts, and you definitely wouldn't be able to play along in time with any music for example. Is there a way to get the sample to sound instantly as soon as it's pressed on a mobile device? I've found that the "mousedown" event seems to work best for desktop, but I can't get the same result with anything that I have tried for mobile.

请随时在此处查看Beat pad项目: http://beatpad.dwcreate. co.uk/

Please feel free to take a look at the Beat pad project here: http://beatpad.dwcreate.co.uk/

如果需要,我稍后再发布代码.

I'll post code later if needed.

非常感谢任何可以帮助我解决这个问题的人!

Many thanks to anyone who can help me with this problem!

推荐答案

Audio元素似乎在Apple触摸设备上存在延迟问题...对其他设备不确定. AudioBuffer将提供跨浏览器的更可靠的即时回放.经过一番摆弄之后,似乎"touchstart"事件必须绑定到文档上,并且在绑定到元素上时不起作用.

Audio element seems to have latency issues on Apple touch devices...not sure about the others. AudioBuffer will provide more reliable playback immediacy across browsers. After some fiddling, it seems the "touchstart" event must be bound on the document and wasn't working when bound on the element.

// 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://batman.dev/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>

这篇关于在移动设备上按下时,如何使Web Audio元素立即发出声音?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆