前端:音频可视化(VUE3+TS版本)

一、效果展示

音频可视化vue组件版本

二、代码

<template>
  <div class="audioPage" ref="audioPageRef" @click="palyMusic()">
    <canvas ref="canvasRef" width="100" height="100"></canvas>

    <audio ref="audioRef">
      <source src="../../assets/audio/游戏城大冒险.mp3" />
    </audio>
  </div>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
const audioRef = ref();
const canvasRef = ref();
const audioPageRef = ref();
//需要可视化的数据
let audioArr: Uint8Array = new Uint8Array();
//我们需要一个音乐播放器和一个canvas进行显示
const radius = 20; // 圆的半径
let analyser: any = null;
//初始化
let isInit = false;

onMounted(() => {
  drawGradientCircle(); // 绘制圆形
  // 当音乐播放
  audioRef.value.onplay = () => {
    if (!isInit) {
      isInit = true;
    }

    const audioContext = new AudioContext(); // 创建音频上下文
    const audioSrc = audioContext.createMediaElementSource(audioRef.value); // 创建音频源
    analyser = audioContext.createAnalyser(); // 创建分析器
    analyser.fftSize = 64; // 设置傅里叶变换的大小,影响线条密度
    audioArr = new Uint8Array(analyser.frequencyBinCount); // 创建一个无符号字节数组存储频率数据,该API参考ES6文档
    audioSrc.connect(analyser); // 连接音频源和分析器
    analyser.connect(audioContext.destination); // 连接分析器和音频目的地

    //动画开始
    animate();
  };
});

// 绘制圆形
const drawGradientCircle = () => {
  const ctx = canvasRef.value.getContext("2d");
  const centerX = canvasRef.value.width / 2;
  const centerY = canvasRef.value.height / 2;
  ctx.beginPath();
  // 创建一个从中心点向外的径向渐变
  const grd = ctx.createLinearGradient(
    centerX - radius,
    centerY - radius,
    centerX + radius,
    centerY + radius
  );
  grd.addColorStop("0", "purple");
  grd.addColorStop("0.3", "magenta");
  grd.addColorStop("0.5", "blue");
  grd.addColorStop("0.6", "green");
  grd.addColorStop("0.8", "yellow");
  grd.addColorStop(1, "red");

  ctx.strokeStyle = grd;

  ctx.arc(centerX, centerY, radius - 2, 0, Math.PI * 2); // 绘制一个完整的圆

  ctx.stroke(); // 画圆复制代码
};

//绘制线条
const drawLinesFromCircle = () => {
  const ctx = canvasRef.value.getContext("2d");
  const centerX = canvasRef.value.width / 2;
  const centerY = canvasRef.value.height / 2;
  ctx.lineWidth = 2;

  //使用音频的频率数据绘制线条
  //为了美观,我们绘制两条线,一条是频率数据,另一条是对称的
  //也可以去使用其它的方式绘制线条
  audioArr.forEach((value, index) => {
    const baseAngle = (index / audioArr.length) * Math.PI * 2; // 基础角度
    const angle1 = baseAngle; // 第一条线的角度
    const angle2 = baseAngle + Math.PI; // 对称线的角度,相差π(180度)

    // 绘制第一条线
    {
      const endX1 = centerX + radius * Math.cos(angle1);
      const endY1 = centerY + radius * Math.sin(angle1);
      const startX1 = centerX + (radius + value * 0.1) * Math.cos(angle1); // 使用value控制长度
      const startY1 = centerY + (radius + value * 0.1) * Math.sin(angle1);

      ctx.beginPath();
      ctx.moveTo(startX1, startY1);
      ctx.lineTo(endX1, endY1);
      ctx.strokeStyle = `hsl(${index * 3.6}, 100%, 50%)`;
      ctx.stroke();
    }

    // 绘制对称的第二条线
    {
      const endX2 = centerX + radius * Math.cos(angle2);
      const endY2 = centerY + radius * Math.sin(angle2);
      const startX2 = centerX + (radius + value * 0.1) * Math.cos(angle2);
      const startY2 = centerY + (radius + value * 0.1) * Math.sin(angle2);

      ctx.beginPath();
      ctx.moveTo(startX2, startY2);
      ctx.lineTo(endX2, endY2);
      ctx.strokeStyle = `hsl(${
        (index + audioArr.length / 2) * 3.6
      }, 100%, 50%)`; // 调整颜色以保持对称性且有所区别
      ctx.stroke();
    }
  });
};

//播放动画
const animate = () => {
  const ctx = canvasRef.value.getContext("2d");
  ctx.clearRect(0, 0, canvasRef.value.width, canvasRef.value.height); // 清除画布
  if (!isInit) return;
  analyser.getByteFrequencyData(audioArr); // 获取频率数据
  drawGradientCircle(); // 绘制圆形
  drawLinesFromCircle(); // 绘制伸展的线条
  requestAnimationFrame(animate); // 重复绘制以创建动画效果
};

const palyMusic = () => {
  if (audioRef.value.paused) {
    audioRef.value.play();
  } else {
    audioRef.value.pause();
  }
};
</script>
<style scoped lang="scss">
.audioPage {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;

  cursor: pointer;
}
</style>

三、H5+JS版本

前端:音频可视化(H5+js版本)-CSDN博客

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值