Web Audio API 实践

这段代码直接引入即可,需要保证有 #app 元素存在且 /music.ogg 音频可以被获取到。

这段代码会在页面内生成一个 canvasaudio 元素。

点击了 audio 元素的播放按钮之后,就能够在一旁的 canvas 上看见音频可视化内容了。

const canvas = document.createElement('canvas')
const music = document.createElement('audio')
const app = document.querySelector('#app')

/**
 * canvas 2d 上下文
 */
const ctx = canvas.getContext('2d')!

/**
 * audio 上下文
 */
const audio = new AudioContext()

/**
 * 音频源
 */
const source = audio.createMediaElementSource(music)

/**
 * 分析器
 */
const analyser = audio.createAnalyser()

/**
 * 音量设置
 */
const gain = audio.createGain()

/**
 * 数据数组 数组大小为 analyser.frequencyBinCount
 */
const dataArray = new Uint8Array(analyser.frequencyBinCount)

/**
 * 盒子大小
 */
const boxSize = 500

/**
 * 原点半径
 */
const originRadius = 100

/**
 * 原点 x 轴
 */
const originX = boxSize / 2

/**
 * 原点 y 轴
 */
const originY = boxSize / 2

/**
 * 原点线条最大长度
 */
const originLine = boxSize / 2

/**
 * 圆弧角度
 */
const arg = Math.PI / 720

/**
 * 源音频
 */
const sourceAudio = '/music.ogg'

canvas.height = boxSize
canvas.width = boxSize

function draw () {
  ctx.clearRect(0, 0, canvas.width, canvas.height) // 清除 canvas
  // 移动到原点x轴 + 半径位置,原点y轴
  // 直接移动到原点x轴,原点y轴,绘制圆时会从原点延伸一条线条到边框
  ctx.moveTo(originX + originRadius, originY)
  ctx.strokeStyle = 'pink' // 线条颜色为 粉色
  // 绘制圆,并加粗
  ctx.arc(originX, originY, originRadius - 2, 0, Math.PI * 2, true)
  ctx.arc(originX, originY, originRadius - 1, 0, Math.PI * 2, true)
  ctx.arc(originX, originY, originRadius, 0, Math.PI * 2, true)
  ctx.stroke() // 绘制线条
  analyser.getByteFrequencyData(dataArray) // 获取频谱数据

  // 2304 是 64 和 36 的乘积
  // 因为频谱数据长度为64位
  for (let i = 0; i < 2304; i += 36) {
    let len = originRadius + dataArray[i / 36] // 生成延伸线条长度
    len = len > originLine ? originLine : len // 判断边界
    ctx.beginPath()
    // 生成随机颜色
    ctx.strokeStyle = '#' + Math.random().toString(16).substring(2, 6)
    // 绘制圆
    ctx.arc(originX, originY, originRadius, arg * i, arg * i, false)
    // 延伸线条
    ctx.arc(originX, originY, len, arg * i, arg * i, false)
    // 回退线条 若不如此 则会直接移动到原点绘制圆 导致从原点延伸线条
    ctx.arc(originX, originY, originRadius, arg * (i + 1), arg * (i + 1), false)
    // 延伸线条 加粗
    ctx.arc(originX, originY, len, arg * (i + 1), arg * (i + 1), false)
    // 回退线条
    ctx.arc(originX, originY, originRadius, arg * (i - 1), arg * (i - 1), false)
    // 延伸线条 加粗
    ctx.arc(originX, originY, len, arg * (i - 1), arg * (i - 1), false)
    ctx.stroke()
    ctx.closePath()
  }
  requestAnimationFrame(draw)
}


music.controls = true
// music.src = '/music.ogg'
music.src = sourceAudio
music.onplay = () => {
  analyser.fftSize = 128
  gain.gain.value = 1
  source.connect(gain)
  gain.connect(analyser)
  analyser.connect(audio.destination)

  draw()
}

app?.append(canvas, music)


Web Audio API 实践
http://localhost:8080/archives/web-audio-api-shi-jian
作者
inksha
发布于
2024年09月20日
许可协议