JavaScript 音频可视化

html,
body {
    margin: 0;
    padding: 0;
    height: 100%;
    width: 100%;
    overflow: hidden;
}

#upload {
    position: fixed;
    top: 0;
    left: 0;
}

audio {
    position: fixed;
    top: 0;
    right: 0;
}
<input type="file" id="upload" accept="audio/mpeg">
  const upload = document.querySelector('#upload')

  upload.addEventListener('change', (e) => {
    const [file] = e.target.files
    if (!file) upload.value = ''
    const { type } = file
    if (!type.includes('audio')) {
      alert('仅支持音频格式文件')
      upload.value = ''
      return false
    }
    const url = URL.createObjectURL(file)
    draw(url)
  })

  function draw(url) {
    const {
      clientWidth: width,
      clientHeight: height,
    } = document.body
    const audio = new Audio
    audio.src = url
    audio.controls = true
    audio.load()
    const canvas = document.createElement('canvas')
    canvas.width = width
    canvas.height = height
    document.body.appendChild(audio)
    document.body.appendChild(canvas)
    const canvasCtx = canvas.getContext('2d')
    const audioCtx = new AudioContext
    const sourceNode = audioCtx.createMediaElementSource(audio)
    // 音频分析器
    const analyser = audioCtx.createAnalyser()
    analyser.fftSize = 128 // FFT
    sourceNode.connect(analyser)
    analyser.connect(audioCtx.destination)
    const len = analyser.frequencyBinCount
    const buffer = new Uint8Array(len)
    const gap = 2 // 间隙
    const pillarWidth = (width / len) - gap
    const gradient = canvasCtx.createLinearGradient(0, 0, 0, 500)
    gradient.addColorStop(.8, '#1eec1e')
    gradient.addColorStop(.5, '#c97a3d')
    gradient.addColorStop(0, '#f00f00')

    const render = () => {
      canvasCtx.fillStyle = '#fff'
      canvasCtx.fillRect(0, 0, width, height)
      analyser.getByteFrequencyData(buffer)
      let x = 0
      buffer.forEach(v => {
        const pillarHeight = (v / 255) * height
        canvasCtx.fillStyle = gradient
        canvasCtx.fillRect(x, height - (pillarHeight || 2), pillarWidth, pillarHeight || 2)
        x += (pillarWidth + gap)
      })
      requestAnimationFrame(render)
    }
    render()
    audio.play()
  }
posted @ 2021-01-07 14:27  demo_you  阅读(664)  评论(0编辑  收藏  举报