<template>
  <div class="audio-waveform">
    <canvas ref="canvas" width="288" height="48"></canvas>
  </div>
</template>

<script setup>
import { ref, watch, onMounted, onBeforeUnmount } from 'vue'
const props = defineProps({
  pcmData: {
    type: Array,
    default: () => []
  }
})
const canvas = ref(null)
const BAR_COUNT = 48 // 波形条数量
const latestPcm = ref([])
let animationId = null
const currentHeights = ref(Array(BAR_COUNT).fill(4)) // 当前每根条的高度（用于平滑动画）
let targetHeights = Array(BAR_COUNT).fill(4) // 目标高度

const BAR_WIDTH = 3 // 波形条宽度
const BAR_GAP = 3   // 波形条间距
const CANVAS_WIDTH = BAR_COUNT * (BAR_WIDTH + BAR_GAP) // 画布宽度
const CANVAS_HEIGHT = 48 // 画布高度
const RADIUS = BAR_WIDTH / 2 // 圆角半径

// 计算每根波形条的目标高度（核心算法）
const calcTargetHeights = (pcm) => {
  if (!pcm || pcm.length === 0) return Array(BAR_COUNT).fill(4)
  const step = Math.floor(pcm.length / BAR_COUNT)
  const maxBarHeight = 22 // 单边最大高度
  const THRESHOLD = 8 // 门限，低于此值视为静止
  let maxRms = 1
  const rmsArr = []
  // 计算每根条的RMS能量，并找出最大值
  for (let i = 0; i < BAR_COUNT; i++) {
    let sum = 0
    for (let j = 0; j < step; j++) {
      const idx = i * step + j
      sum += (pcm[idx] || 0) * (pcm[idx] || 0)
    }
    const rms = Math.sqrt(sum / step)
    rmsArr[i] = rms < THRESHOLD ? 0 : rms - THRESHOLD // 门限抑制底噪
    maxRms = Math.max(maxRms, rmsArr[i])
  }
  const norm = Math.max(32, maxRms) // 归一化因子，防止全静止
  const arr = []
  for (let i = 0; i < BAR_COUNT; i++) {
    // 非线性提升对比度，指数越大，只有大信号才有明显变化
    const ratio = Math.pow(rmsArr[i] / norm, 1.2)
    arr[i] = 4 + Math.min(1, ratio) * maxBarHeight // 4为最小高度
  }
  return arr
}

// 绘制波形（每帧调用）
const drawWave = () => {
  if (!canvas.value) return
  const ctx = canvas.value.getContext('2d')
  ctx.clearRect(0, 0, canvas.value.width, canvas.value.height)
  const centerY = canvas.value.height / 2
  for (let i = 0; i < BAR_COUNT; i++) {
    // 平滑过渡动画：当前高度逐步靠近目标高度
    currentHeights.value[i] = currentHeights.value[i] * 0.7 + targetHeights[i] * 0.3
    const barHeight = currentHeights.value[i]
    const x = i * (BAR_WIDTH + BAR_GAP) + BAR_GAP / 2
    ctx.fillStyle = 'rgba(255,255,255,0.6)'
    // 画中间矩形
    ctx.fillRect(x, centerY - barHeight + RADIUS, BAR_WIDTH, barHeight * 2 - RADIUS * 2)
    // 画顶部半圆
    ctx.beginPath()
    ctx.arc(x + BAR_WIDTH / 2, centerY - barHeight + RADIUS, RADIUS, Math.PI, 0)
    ctx.closePath()
    ctx.fill()
    // 画底部半圆
    ctx.beginPath()
    ctx.arc(x + BAR_WIDTH / 2, centerY + barHeight - RADIUS, RADIUS, 0, Math.PI)
    ctx.closePath()
    ctx.fill()
  }
}

// 动画主循环，保证高帧率刷新
const animate = () => {
  drawWave()
  animationId = requestAnimationFrame(animate)
}

// 监听PCM数据变化，更新目标高度
watch(() => props.pcmData, (val) => {
  latestPcm.value = val
  targetHeights = calcTargetHeights(val)
})

// 组件挂载时启动动画
onMounted(() => {
  latestPcm.value = props.pcmData
  targetHeights = calcTargetHeights(props.pcmData)
  // 设置canvas宽高
  if (canvas.value) {
    canvas.value.width = CANVAS_WIDTH
    canvas.value.height = CANVAS_HEIGHT
  }
  animate()
})

// 组件卸载时停止动画
onBeforeUnmount(() => {
  if (animationId) cancelAnimationFrame(animationId)
})
</script>

<style scoped>
.audio-waveform {
  width: 100%;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.audio-waveform canvas {
  width: 288px;
  height: 48px;
  display: block;
  background: transparent;
}
</style> 