javascript - 使用 Javascript 进行拍手检测

标签 javascript web-audio-api

我对这个问题很陌生,但我尝试了这样的事情。

我知道 Audio api 很强大,但我不太了解,所以我来了:

let asClap = false;
let tampon = 60;
navigator.mediaDevices.getUserMedia({
  "audio": {
      "mandatory": {
          "googEchoCancellation": "false",
          "googAutoGainControl": "false",
          "googNoiseSuppression": "false",
          "googHighpassFilter": "false"
      },
      "optional": []
  },
}).then(function(stream) {
    
    const audioContext = new AudioContext();
    
    /* use the stream */
    let gain_node = audioContext.createGain();
    gain_node.connect( audioContext.destination );
    
    let microphone_stream = audioContext.createMediaStreamSource(stream);
    
    let analyser = audioContext.createAnalyser()
    microphone_stream.connect(analyser)
    analyser.fftSize = 256;
    isClaping(analyser)
   

  }).catch(function(err) {
    console.log(err)
});




function isClaping(analyser){
  const bufferLength = analyser.frequencyBinCount;
  var data = new Uint8Array(bufferLength);
  analyser.getByteFrequencyData(data);
  
  const arraySum = data.reduce((a, value) => a + value);
  if(arraySum >= 3000){   
    if(!asClap){
      asClap = true;
      clap()
    }
  }
  requestAnimationFrame(()=>{isClaping(analyser)});
  tampon--
  if(tampon === 0){
    tampon = 60
    asClap = false
  }
}

我真的需要用 Javascript 来做,因为我更熟悉 这是正确的吗?我如何检测双拍?

最佳答案

这是一个用于检测拍手的简单能量分析器。它将 2200-2800 频率范围内的振幅相加,并在该能量超过阈值时触发事件。


export class ClapDetector {

  options = {
    // energy threshold for claps
    clapThreshold: 70,
    // typical freq range for claps
    highFrequencyRange: [2200, 2800],
    minClapInterval: 300
  }

  lastClapTime: number = 0
  frameRequeust: number = null
  bufferLength: number = 0
  analyserNode: AnalyserNode = null
  frequencyData: Uint8Array = null
  audioContext: AudioContext = null

  constructor(options = {}) {
    this.options = Object.assign(this.options, options)
    this.lastClapTime = 0
    this.detectClap = this.detectClap.bind(this)

    this.audioContext = new AudioContext()
    this.analyserNode = this.audioContext.createAnalyser()
    // high frequency, short fft size
    this.analyserNode.fftSize = 2048
    this.analyserNode.minDecibels = -90
    this.analyserNode.maxDecibels = -10
    this.analyserNode.smoothingTimeConstant = 0.85

    this.bufferLength = this.analyserNode.frequencyBinCount
    this.frequencyData = new Uint8Array(this.bufferLength)

    navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {
      const mediaStreamSource = this.audioContext.createMediaStreamSource(stream)
      // connect the mediaStreamSource to the analyserNode
      mediaStreamSource.connect(this.analyserNode)
      this.start()
    })

  }

  start() {
    this.frameRequeust = requestAnimationFrame(this.detectClap)
  }

  stop() {
    cancelAnimationFrame(this.frameRequeust)
  }

  detectClap() {
    this.analyserNode.getByteFrequencyData(this.frequencyData)

    const highFrequencyData = this.frequencyData.slice(
      Math.round(this.options.highFrequencyRange[0] / this.audioContext.sampleRate * this.bufferLength),
      Math.round(this.options.highFrequencyRange[1] / this.audioContext.sampleRate * this.bufferLength)
    )
    const highFrequencyEnergy = highFrequencyData.reduce((sum, value) => sum + value) / highFrequencyData.length
    console.log(highFrequencyEnergy)

    const metClapThreshold = highFrequencyEnergy > this.options.clapThreshold
    const timeSinceLastClap = Date.now() - this.lastClapTime
    const metMinClapInterval = timeSinceLastClap > this.options.minClapInterval
    if (metClapThreshold && metMinClapInterval) {
      console.log('Clap detected!')
      this.lastClapTime = Date.now()
      this.clapListeners.forEach(listener => listener())
    }

    this.frameRequeust = requestAnimationFrame(this.detectClap)
  }

  clapListeners = []
  // add listener
  onClap(listener) {
    this.clapListeners.push(listener)
  }
  // remove listener
  offClap(listener) {
    this.clapListeners = this.clapListeners.filter(l => l !== listener)
  }

}

如果您想检测双拍,您可以添加一个选项来检查最大时间阈值,并触发双拍处理程序。

    if (metClapThreshold && metMinClapInterval) {
      //...
      const underMaxDoubleClapInterval = timeSinceLastClap < this.options.maxDoubleClapInterval
      if(underMaxDoubleClapInterval) {
        this.doubleClapListeners.forEach(listener => listener())

        // increase last clap time to prevent unlimited double claps
        this.lastClapTime += this.options.maxDoubleClapInterval
      }
    }

关于javascript - 使用 Javascript 进行拍手检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72092757/

相关文章:

javascript - javascript iffy结构之间的区别

javascript - 报警功能无法正常工作

javascript - 将时间码转换为秒

javascript - 使用 Web Audio API 创建 10 波段均衡器

javascript - 如何控制输出增益?

javascript - 将 AngularJS 指令迁移到 Angular 2.x+ 指令作为 HTML 装饰器

javascript - 防止滚动条出现在变换上 : translate with React-Spring

javascript - 使用 <audio> 元素播放原始音频

javascript - Web 音频 API 的 Soundcloud CORS 错误

javascript - 如何生成HTML5视频音量水平图?